Compare commits

...
10 Commits
Author SHA1 Message Date
krosh c29d366255 2026 UPDATE!!! 2026-03-01 00:49:27 +03:00
krosh 65a63b5596 . 2025-03-09 19:08:25 +03:00
krosh 82a2a5dafb another fixes 2025-03-09 08:19:30 +03:00
krosh e616a28fbe some upd 2025-03-06 17:06:46 +03:00
krosh 20dbcaac62 . 2025-03-06 16:56:04 +03:00
krosh a0c0726865 text update 2025-03-06 16:44:28 +03:00
krosh 9cda21ea29 bug fix 2025-03-03 20:42:31 +03:00
krosh 67b708bdff close port for internet :) 2025-03-03 18:56:29 +03:00
krosh 4692287d41 . 2025-03-01 01:56:31 +03:00
krosh a688a19b4e some fixs 2025-03-01 01:49:33 +03:00
30 changed files with 694 additions and 239 deletions
+10
View File
@@ -0,0 +1,10 @@
DATE_START=2024-07-01
TIME_START=12:00
API_TOKEN="your_api_token_here"
ADMIN_ID=your_admin_id_here
DB_PORT=27017
ENV=PROD
SSH_HOST=your_ssh_host_here
SSH_USER=your_ssh_user_here
SSH_KEY=path_to_your_ssh_key_here
SSH_PASSWORD=your_ssh_password_here
Regular → Executable
+204 -17
View File
@@ -1,20 +1,207 @@
# Ignore everything # Byte-compiled / optimized / DLL files
*
# Except these files
!.gitignore
!docker-compose.yaml
!requirements.txt
!readme.md
# Except these directories and their contents
!/app
!/app/*
!/app/plugin
!/app/plugin/*
# Ignore specific files and directories
app/bot.py
__pycache__/ __pycache__/
*.py[codz]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
#poetry.toml
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/
# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env .env
.envrc
.venv .venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/
# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
# Ruff stuff:
.ruff_cache/
# PyPI configuration file
.pypirc
# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore
# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/
Regular → Executable
+29 -16
View File
@@ -12,7 +12,7 @@ class config:
"%Y-%m-%d-%H:%M", "%Y-%m-%d-%H:%M",
) )
API_TOKEN = os.environ.get("API_TOKEN") API_TOKEN = os.environ.get("API_TOKEN")
ADMIN_ID = os.environ.get("ADMIN_ID") ADMIN_ID = int(os.environ.get("ADMIN_ID"))
ENV = os.getenv("ENV", "PROD") ENV = os.getenv("ENV", "PROD")
DB_PORT = int(os.getenv("DB_PORT", 27017)) DB_PORT = int(os.getenv("DB_PORT", 27017))
@@ -31,33 +31,46 @@ class config:
class Messages: class Messages:
WELCOME_LIST = [ WELCOME_LIST = [
"Привет! Это бот Quick dates (Random Coffee). Чтобы зарегистрироваться, пожалуйста, ответь на следующие вопросы." # несколько сообщений подряд (
"Привет! Это бот <b>Random Coffee</b>."
"\n\nЧтобы зарегистрироваться, ответь на следующие вопросы ⬇️"
) # несколько сообщений подряд
] ]
HELPS = [ HELPS = [
"Доступные команды:" "\n/start - начать регистрацию", (
"\n/help - помощь", "Доступные команды:"
"\n/source - исходный код бота на Github", "\n/start - начать регистрацию"
"\n\nCreated by АйТи блок ВМК with love ❤️", "\n/help - помощь"
# "Начало мероприятия: {} \nЭто через целых {} минут!", "\n/source - исходный код бота на Github"
"\n\nCreated by АйТи блок ВМК with love ❤️"
)
] ]
ERROR = "Произошла ошибка" ERROR = "Произошла ошибка"
ENTER_NAME = "Как тебя зовут?" ENTER_NAME = "Как тебя зовут?"
ENTER_AGE = "Сколько тебе лет?" ENTER_AGE = "Сколько тебе лет?"
ENTER_GENDER = "Выбери пол (женский, мужской)" ENTER_GENDER = "Выбери пол"
GENDER_WOMAN = "Я девушка" # кнопки выбора GENDER_WOMAN = "Я девушка" # кнопки выбора
GENDER_MAN = "Я парень" # кнопки выбора GENDER_MAN = "Я парень" # кнопки выбора
ENTER_FACULTY = "С какого ты факультета?" ENTER_FACULTY = "С какого ты факультета?"
ENTER_GROUP = "Напиши номер своей группы" ENTER_GROUP = "Напиши номер своей группы"
REGISTRATION_CONFIRM = "Ты ввел следующие данные:\ ENTER_AGREE_UPLOAD = (
\n\nИмя: {}\ "Согласен ли ты на сохранение своих данных в общую базу для подбора пар?"
\nВозраст: {}\ )
\nПол: {}\ REGISTRATION_CONFIRM = "<u>Твои данные:</u>\
\nФакультет: {}\ \n\n<b>Имя:</b> {}\
\nГруппа: {}\ \n<b>Возраст:</b> {}\
\n<b>Пол:</b> {}\
\n<b>Факультет:</b> {}\
\n<b>Группа:</b> {}\
\n<b>Согласие на сохранение данных:</b> {}\
\n\nВсё верно?" \n\nВсё верно?"
ALREADY_REGISTERED = "Ты уже зарегистрирован. Хочешь изменить данные?" ALREADY_REGISTERED = "Ты уже зарегистрирован. Хочешь изменить данные?"
MATCHING_START = ( MATCHING_START = (
"Мы начали подбор пар. Пожалуйста, подтверди, что ты находишься в аудитории" "Мы начали подбор пар 🤩" "\nПодтверди своё нахождение в аудитории."
)
START_DATE = (
"Мероприятие начнётся:"
"\n🗓️ <b>3 апреля в 18:00</b>"
"\n\nСледите за новостями!"
) )
START_DATE = f"Наше мероприятие начнётся {os.environ.get('DATE_START')} следите за новостями!"
Regular → Executable
+4 -2
View File
@@ -3,17 +3,19 @@ from config import config
class DB: class DB:
client = pymongo.MongoClient(f"mongodb://localhost:{config.DB_PORT}/") client = pymongo.MongoClient(f"mongodb://mongo:{config.DB_PORT}/")
db = client["rc_coffee"] db = client["rc_coffee"]
def __init__(self, collection): def __init__(self, collection):
if collection not in self.db.list_collection_names():
self.db.create_collection(collection)
self.collection = self.db[collection] self.collection = self.db[collection]
def insert(self, data): def insert(self, data):
self.collection.insert_one(data) self.collection.insert_one(data)
def find(self, query): def find(self, query):
return self.collection.find(query) return list(self.collection.find(query))
def find_one(self, query): def find_one(self, query):
return self.collection.find_one(query) return self.collection.find_one(query)
Regular → Executable
+42 -13
View File
@@ -1,7 +1,3 @@
import os
import sys
import telebot
import threading
from config import config, Messages from config import config, Messages
from telebot import types from telebot import types
from plugin.user import User from plugin.user import User
@@ -42,9 +38,10 @@ def start_message(message: types.Message):
Messages.REGISTRATION_CONFIRM.format( Messages.REGISTRATION_CONFIRM.format(
user.name, user.name,
user.age, user.age,
user.gender, "Парень" if user.gender == "man" else "Девушка",
user.faculty, user.faculty,
user.group, user.group,
"Да" if user.agree_upload else "Нет",
), ),
reply_markup=markup, reply_markup=markup,
) )
@@ -66,7 +63,7 @@ def help_message(message: types.Message):
for msg in Messages.HELPS: for msg in Messages.HELPS:
bot.send_message(message.chat.id, msg) bot.send_message(message.chat.id, msg)
else: else:
bot.send_message(message.chat.id, AdminMessages.ADMIN_HELP, parse_mode="HTML") bot.send_message(message.chat.id, AdminMessages.ADMIN_HELP)
return return
@@ -75,15 +72,43 @@ def help_message(message: types.Message):
def source(message: types.Message): def source(message: types.Message):
bot.send_message( bot.send_message(
message.chat.id, message.chat.id,
"[Страничка бота на Github!](https://github.com/kr0sh512/rc-tgbot)", (
parse_mode="Markdown", "<a href='https://github.com/kr0sh512/rc-tgbot'>Страничка бота на Github!</a>"
"\n\nСтарался раб профкомский <a href='https://t.me/kr0sh_512'>Дмитрий</a>. mewow."
),
) )
return return
@bot.message_handler(func=lambda message: True)
def handle_all_messages(message: types.Message):
help_message(message)
if __name__ == "__main__": if __name__ == "__main__":
print("/t--- Bot started ---") print("\t--- Bot started ---")
admins = Admin.get_all_admins()
print(admins)
print(Admin._db.find({}))
print([(data, "user_id" in data) for data in Admin._db.find({})])
for admin in admins:
bot.send_message(
admin.user_id,
"Служебное сообщение: бот был перезапущен.",
)
# Test connection to the database
try:
User.get_all()
print("Database connection successful.")
except Exception as e:
print(f"Database connection failed: {e}")
time_for_notif = config.DATE_START time_for_notif = config.DATE_START
@@ -92,16 +117,20 @@ if __name__ == "__main__":
users = User.get_all() users = User.get_all()
for user in users: for user in users:
bot.send_message( bot.send_message(
user["user_id"], user.user_id,
"Напоминание, что наше мероприятие пройдёт уже завтра! Следите за новостями)", "Напоминание, что наше мероприятие пройдёт уже завтра! Следите за новостями)",
) )
if len(user.type) != 4:
bot.send_message(
user.user_id,
"Вы ещё не прошли тест! Пожалуйста, пройдите его, чтобы мы могли вас зарегистрировать.",
)
admins = Admin.get_all_admins() admins = Admin.get_all_admins()
for admin in admins: for admin in admins:
bot.send_message( bot.send_message(
admin["user_id"], admin.user_id,
"Отправлено напоминание о скором начале мероприятия.", "Отправлено напоминание о скором начале мероприятия.",
) )
time.sleep(10) time.sleep(10)
exit()
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 612 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Regular → Executable
+56 -45
View File
@@ -1,9 +1,9 @@
from db import DB from db import DB
import config from config import config
import os import os
import threading import threading
import time import time
from plugin.user import User from plugin.user import User, users_reg
from plugin.shuffle import Shuffle, already_matched from plugin.shuffle import Shuffle, already_matched
from plugin.bot_instance import bot from plugin.bot_instance import bot
@@ -26,7 +26,7 @@ class Admin:
data = self._db.find_one({"user_id": self.user_id}) data = self._db.find_one({"user_id": self.user_id})
if data: if data:
self.name = data["name"] self.name = data["name"]
self.added_by = data["added_by"] self.added_by = data.get("added_by")
else: else:
raise ValueError("Admin not found") raise ValueError("Admin not found")
@@ -34,17 +34,21 @@ class Admin:
@staticmethod @staticmethod
def get_all_admins(): def get_all_admins():
return Admin._db.find({}) return [
Admin(data["user_id"]) for data in Admin._db.find({}) if "user_id" in data
]
@staticmethod @staticmethod
def is_admin(user_id): def is_admin(user_id):
return Admin._db.find({"user_id": user_id}) is not None return (Admin._db.find_one({"user_id": user_id}) is not None) or (
user_id == config.ADMIN_ID
)
@staticmethod @staticmethod
def add_admin(new_user_id, name, unique_key) -> int: def add_admin(new_user_id, name, unique_key) -> int:
key_data = Admin._db.find_one({"unique_key": unique_key}) key_data = Admin._db.find_one({"unique_key": unique_key})
if new_user_id == config.ADMIN_ID and not Admin.is_admin(new_user_id): if new_user_id == config.ADMIN_ID:
Admin._db.insert({"user_id": new_user_id, "name": name}) Admin._db.insert({"user_id": new_user_id, "name": name})
return new_user_id return new_user_id
@@ -105,6 +109,7 @@ class Admin:
# ----------------- TELEBOT ----------------- # # ----------------- TELEBOT ----------------- #
def admin_only(func): def admin_only(func):
def wrapper(message, *args, **kwargs): def wrapper(message, *args, **kwargs):
if Admin.is_admin(message.chat.id): if Admin.is_admin(message.chat.id):
return func(message, *args, **kwargs) return func(message, *args, **kwargs)
@@ -147,7 +152,6 @@ class Admin:
bot.send_message( bot.send_message(
message.chat.id, message.chat.id,
"Ваш ключ: <code>{}</code>".format(key), "Ваш ключ: <code>{}</code>".format(key),
parse_mode="HTML",
) )
except Exception as e: except Exception as e:
bot.send_message(message.chat.id, str(e)) bot.send_message(message.chat.id, str(e))
@@ -198,7 +202,7 @@ class Admin:
f.write("Количество пользователей: {}\n".format(len(users))) f.write("Количество пользователей: {}\n".format(len(users)))
for user in users: for user in users:
f.write(str(user) + "\n") f.write(str(user) + "\n\n")
with open("stats.txt", "rb") as f: with open("stats.txt", "rb") as f:
bot.send_document(message.chat.id, f) bot.send_document(message.chat.id, f)
@@ -208,7 +212,7 @@ class Admin:
f.write("Количество админов: {}\n".format(len(admins))) f.write("Количество админов: {}\n".format(len(admins)))
for admin in admins: for admin in admins:
f.write(str(admin) + "\n") f.write(str(admin) + "\n\n")
with open("admin_stats.txt", "rb") as f: with open("admin_stats.txt", "rb") as f:
bot.send_document(message.chat.id, f) bot.send_document(message.chat.id, f)
@@ -248,7 +252,6 @@ class Admin:
bot.send_message( bot.send_message(
message.chat.id, message.chat.id,
"Отправьте <code>delete all</code> для подтверждения. \n\nВнимание, вы вряд ли хотите это делать.", "Отправьте <code>delete all</code> для подтверждения. \n\nВнимание, вы вряд ли хотите это делать.",
parse_mode="HTML",
) )
return return
@@ -272,35 +275,29 @@ class Admin:
for admin in Admin.get_all_admins(): for admin in Admin.get_all_admins():
bot.send_message( bot.send_message(
admin["user_id"], admin.user_id,
"Отправлено приглашение пользователем. В данный момент подтвердило участие 0 человек. Запускайте команду /end_random для завершения регистрации", "Отправлено приглашение пользователем. В данный момент подтвердило участие 0 человек.\
\n\n/update чтобы узнать, сколько уже подтвердило участие\
\n\n/end_random для завершения регистрации",
) )
User.start_shuffle_reg() User.start_shuffle_reg()
def monitor_participation(): return
while True:
participants = len(already_matched) @bot.message_handler(commands=["update"])
@admin_only
def update_random_command(message):
bot.send_message( bot.send_message(
message.chat.id, message.chat.id,
f"В данный момент подтвердило участие {participants} человек", f"Подтвердило участие: {len(users_reg)} человек",
) )
time.sleep(5)
thread = threading.Thread(
target=monitor_participation, name="monitor_participation"
)
thread.start()
return return
@bot.message_handler(commands=["end_random", "random_again"]) @bot.message_handler(commands=["end_random", "random_again"])
@admin_only @admin_only
def end_random_command(message): def end_random_command(message):
for thread in threading.enumerate():
if thread.name == "monitor_participation":
thread.kill()
bot.send_message(message.chat.id, "Регистрация завершена. Ожидайте") bot.send_message(message.chat.id, "Регистрация завершена. Ожидайте")
pairs = Shuffle() pairs = Shuffle()
@@ -308,49 +305,63 @@ class Admin:
if pair[1]: if pair[1]:
bot.send_message( bot.send_message(
pair[0].user_id, pair[0].user_id,
f"Ваша пара: {pair[1].name}. Парта находится под номером: {pairs.index(pair) + 1})", f"Твоя пара: {pair[1].name}\n\nНомер парты: {pairs.index(pair) + 1}\n\nХорошего знакомства 🥰",
) )
bot.send_message( bot.send_message(
pair[1].user_id, pair[1].user_id,
f"Ваша пара: {pair[0].name}. Парта находится под номером: {pairs.index(pair) + 1})", f"Твоя пара: {pair[0].name}\n\nНомер парты: {pairs.index(pair) + 1}\n\nХорошего знакомства 🥰",
) )
else: else:
bot.send_message( bot.send_message(
pair[0].user_id, pair[0].user_id,
"Подойди к организаторам мероприятия, они тебе подберут идеальную пару!", (
"✨Счастливый билет✨"
"\n\nПодойди к организаторам мероприятия, они подберут идеальную пару для тебя!"
),
) )
with open("pairs.txt", "w") as f: with open("pairs.txt", "w") as f:
str_pair = ""
for pair in pairs: for pair in pairs:
str_pair += ( if pair[1]:
f.write(
f"Парта {pairs.index(pair) + 1}: {pair[0].name} | {pair[1].name}\n" f"Парта {pairs.index(pair) + 1}: {pair[0].name} | {pair[1].name}\n"
) )
else:
f.write(
f"Парта {pairs.index(pair) + 1}: {pair[0].name} | Нет пары\n"
)
f.write(str_pair)
with open("pairs.txt", "rb") as f:
for admin in Admin.get_all_admins(): for admin in Admin.get_all_admins():
with open("pairs.txt", "rb") as f:
bot.send_document( bot.send_document(
admin["user_id"], admin.user_id,
f, f,
caption="Распредение по парам.",
) )
os.remove("pairs.txt") os.remove("pairs.txt")
return return
@bot.message_handler(commands=["r", "restart"])
@admin_only
def restart_command(message):
# os.system("python3 main.py")
os._exit(0)
return
class AdminMessages: class AdminMessages:
ADMIN_HELP = ( ADMIN_HELP = (
"Вы администратор! Вот что вы можете сделать:\n" "Вы администратор! Вот что вы можете сделать:\n\n"
"/remove_admin - удалить админа\n" "/remove_admin - удалить админа\n\n"
"/generate_key - сгенерировать уникальный ключ (<code>admin_red</code> - чтобы админ добавился)\n" "/generate_key - сгенерировать уникальный ключ (<code>admin_reg</code> - чтобы админ добавился)\n\n"
"/delete_user - удалить пользователя\n" "/delete_user - удалить пользователя\n\n"
"/stats - статистика\n" "/stats - статистика\n\n"
"/send_message - отправить всем сообщение\n" "/send_message - отправить всем сообщение\n\n"
"/random - зарандомить людей для 1 тура\n" "/random - зарандомить людей для 1 тура\n\n"
"/random_again - зарандомить людей без повторной регистрации\n" "/random_again - зарандомить людей без повторной регистрации\n\n"
"<code>clear_all</code> - удаляет ВСЕХ пользователей для их повторной регистрации\n" "<code>clear_all</code> - удаляет ВСЕХ пользователей для их повторной регистрации\n\n"
"/restart - перезапуск бота\n\n"
"/source - исходный код бота на Github"
) )
Regular → Executable
+9 -2
View File
@@ -14,15 +14,21 @@ original_send_message = telebot.TeleBot.send_message
def send_message_with_try_catch(self, chat_id, text, *args, **kwargs): def send_message_with_try_catch(self, chat_id, text, *args, **kwargs):
print("test_msg")
try: try:
return original_send_message(self, chat_id, text, *args, **kwargs) return original_send_message(
self, chat_id, text, parse_mode="HTML", *args, **kwargs
)
except Exception as e: except Exception as e:
print(f"Error sending message: {e}. Retrying in 5 seconds...") print(f"Error sending message: {e}. Retrying in 5 seconds...")
try: try:
time.sleep(5) time.sleep(5)
return original_send_message(self, chat_id, text, *args, **kwargs) return original_send_message(
self, chat_id, text, parse_mode="HTML", *args, **kwargs
)
except Exception as e: except Exception as e:
print(f"Second attempt failed: {e}") print(f"Second attempt failed: {e}")
@@ -32,6 +38,7 @@ telebot.TeleBot.send_message = send_message_with_try_catch
bot = telebot.TeleBot( bot = telebot.TeleBot(
config.API_TOKEN, config.API_TOKEN,
colorful_logs=True, colorful_logs=True,
parse_mode="HTML",
) )
threading.Thread( threading.Thread(
Regular → Executable
+129 -30
View File
@@ -6,18 +6,30 @@ from plugin.test import TestMessages
from plugin.bot_instance import bot from plugin.bot_instance import bot
import os import os
import re import re
import random
def start_reg_name(message: types.Message): def start_reg_name(message: types.Message):
user = User(message.chat.id, message.text) user = User(message.chat.id)
user.name = message.text
bot.send_message(message.chat.id, Messages.ENTER_AGE) bot.send_message(message.chat.id, Messages.ENTER_AGE)
bot.register_next_step_handler(message, start_reg_age) bot.register_next_step_handler(message, start_reg_age)
return
def start_reg_age(message: types.Message): def start_reg_age(message: types.Message):
user = User(message.chat.id) user = User(message.chat.id)
if not message.text.isdigit():
bot.send_message(message.chat.id, "Введите число")
bot.register_next_step_handler(message, start_reg_age)
return
user.age = int(message.text) user.age = int(message.text)
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
@@ -25,9 +37,9 @@ def start_reg_age(message: types.Message):
types.InlineKeyboardButton(Messages.GENDER_WOMAN, callback_data="gender_woman"), types.InlineKeyboardButton(Messages.GENDER_WOMAN, callback_data="gender_woman"),
types.InlineKeyboardButton(Messages.GENDER_MAN, callback_data="gender_man"), types.InlineKeyboardButton(Messages.GENDER_MAN, callback_data="gender_man"),
) )
bot.send_message(message.chat.id, Messages.ENTER_GENDER) bot.send_message(message.chat.id, Messages.ENTER_GENDER, reply_markup=markup)
bot.register_next_step_handler(message, start_reg_gender) return
@bot.callback_query_handler(func=lambda call: "gender" in call.data) @bot.callback_query_handler(func=lambda call: "gender" in call.data)
@@ -60,33 +72,51 @@ def start_reg_group(message: types.Message):
user = User(message.chat.id) user = User(message.chat.id)
user.group = message.text user.group = message.text
markup = types.InlineKeyboardMarkup()
markup.add(
types.InlineKeyboardButton("Согласен", callback_data="upload_agree"),
types.InlineKeyboardButton("Не согласен", callback_data="upload_skip"),
)
bot.send_message(message.chat.id, Messages.ENTER_AGREE_UPLOAD, reply_markup=markup)
return
@bot.callback_query_handler(func=lambda call: "upload" in call.data)
def start_agree_upload(call: types.CallbackQuery):
user = User(call.message.chat.id)
user.agree_upload = call.data.split("_")[-1] == "agree"
bot.edit_message_text(
(
"Согласен на сохранение данных в общую базу"
if user.agree_upload
else "Не согласен на сохранение данных в общую базу"
),
call.message.chat.id,
call.message.message_id,
reply_markup=None,
)
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add( markup.add(
types.InlineKeyboardButton("Всё верно!", callback_data="registration_confirm"), types.InlineKeyboardButton("Всё верно!", callback_data="registration_confirm"),
types.InlineKeyboardButton("Изменить", callback_data="registration_change"), types.InlineKeyboardButton("Изменить", callback_data="registration_change"),
) )
bot.send_message( bot.send_message(
message.chat.id, call.message.chat.id,
Messages.REGISTRATION_CONFIRM.format( Messages.REGISTRATION_CONFIRM.format(
user.name, user.name,
user.age, user.age,
user.gender, "Парень" if user.gender == "man" else "Девушка",
user.faculty, user.faculty,
user.group, user.group,
"Да" if user.agree_upload else "Нет",
), ),
reply_markup=markup, reply_markup=markup,
) )
@bot.callback_query_handler(func=lambda call: call.data == "registration_skip")
def start_skip_reg(call: types.CallbackQuery):
bot.edit_message_reply_markup(
call.message.chat.id, call.message.message_id, reply_markup=None
)
return
@bot.callback_query_handler(func=lambda call: call.data == "registration_change") @bot.callback_query_handler(func=lambda call: call.data == "registration_change")
def start_reg_again(call: types.CallbackQuery): def start_reg_again(call: types.CallbackQuery):
bot.edit_message_reply_markup( bot.edit_message_reply_markup(
@@ -128,33 +158,102 @@ def test_question(call: types.CallbackQuery):
call.message.chat.id, call.message.message_id, reply_markup=None call.message.chat.id, call.message.message_id, reply_markup=None
) )
if len(user.type) == 4: if call.data == "test_yes":
last_q = -1
else:
last_q = int(call.data.split("_")[1].split("#")[0])
previous_ans = int(call.data.split("#")[1])
for ans_type in TestMessages.TEST_QUESTIONS[last_q]["answers"][previous_ans][
"types"
]:
add_score = 3 if last_q == 0 else 2
user.vector_type[ans_type] = user.vector_type.get(ans_type, 0) + add_score
prev_answ = "\n\n".join(
[
f"{'' if i == previous_ans else ''}{i+1}. {ans['text']}"
for i, ans in enumerate(TestMessages.TEST_QUESTIONS[last_q]["answers"])
]
)
prev_text = f"{TestMessages.TEST_QUESTIONS[last_q]['question']}\n\n{prev_answ}"
bot.edit_message_text(
prev_text,
call.message.chat.id,
call.message.message_id,
parse_mode="HTML",
)
if last_q == len(TestMessages.TEST_QUESTIONS) - 1:
max_value = max(user.vector_type.values())
max_types = [t for t, v in user.vector_type.items() if v == max_value]
user.type = random.choice(max_types)
show_result(call.message) show_result(call.message)
return return
if call.data != "test_yes": question = TestMessages.TEST_QUESTIONS[last_q + 1]
user.type += call.data.split("_")[-1] answ = "\n\n".join(
[f"{i+1}. {ans['text']}" for i, ans in enumerate(question["answers"])]
)
text = f"{question['question']}\n\n{answ}"
bot.edit_message_text(
call.message.text
+ "\n\n"
+ TestMessages.TEST_QUESTIONS[len(user.type) - 1]["answers"][
int(call.data[-1])
][0],
call.message.chat.id,
call.message.message_id,
) # упростить
question = TestMessages.TEST_QUESTIONS[len(user.type)]
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
for answer in question["answers"]: for i in range(len(question["answers"])):
markup.add( markup.add(
types.InlineKeyboardButton(answer[0], callback_data=f"test_{answer[1]}") types.InlineKeyboardButton(
f"{question['answers'][i]['short']}",
callback_data=f"test_{last_q + 1}#{i}",
)
) )
bot.send_message(call.message.chat.id, text, reply_markup=markup, parse_mode="HTML")
return return
# @bot.callback_query_handler(func=lambda call: "test" in call.data)
# def test_question(call: types.CallbackQuery):
# user = User(call.message.chat.id)
# bot.edit_message_reply_markup(
# call.message.chat.id, call.message.message_id, reply_markup=None
# )
# if call.data != "test_yes":
# user.type += TestMessages.TEST_QUESTIONS[len(user.type)]["answers"][
# int(call.data[-1])
# ][1]
# user_ans = int(call.data[-1])
# question_last = TestMessages.TEST_QUESTIONS[len(user.type) - 1]
# text_edit = f"{question_last['question']}\n\n{'✅ ' if user_ans == 0 else ''}1. {question_last['answers'][0][0]} \n\n{'✅ ' if user_ans == 1 else ''}2. {question_last['answers'][1][0]}"
# bot.edit_message_text(
# text_edit,
# call.message.chat.id,
# call.message.message_id,
# parse_mode="HTML",
# ) # упростить
# if len(user.type) == 4:
# show_result(call.message)
# return
# question = TestMessages.TEST_QUESTIONS[len(user.type)]
# text = f"{question['question']}\n\n1. {question['answers'][0][0]} \n\n2. {question['answers'][1][0]}"
# markup = types.InlineKeyboardMarkup()
# markup.add(
# types.InlineKeyboardButton("Первый вариант", callback_data=f"test_0"),
# types.InlineKeyboardButton("Второй вариант", callback_data=f"test_1"),
# )
# bot.send_message(call.message.chat.id, text, reply_markup=markup)
# return
def show_result(message: types.Message): def show_result(message: types.Message):
user = User(message.chat.id) user = User(message.chat.id)
text = TestMessages.TEST_RESULT.format( text = TestMessages.TEST_RESULT.format(
Regular → Executable
+1 -1
View File
@@ -11,7 +11,7 @@ def Shuffle() -> List[Tuple[User, User]]:
pairs = [] pairs = []
if len(users) % 2 != 0: if len(users) % 2 != 0:
pairs.append((users.pop(),)) pairs.append((users.pop(), None))
# Step 1: Match men with women by compatibility and age # Step 1: Match men with women by compatibility and age
for user in users: for user in users:
Regular → Executable
+149 -71
View File
@@ -1,124 +1,202 @@
class TestMessages: class TestMessages:
TEST_WELCOME = "Пройди следующий короткий тест, чтобы было легче подобрать тебе пару. А еще ты узнаешь, кто ты из героев советских мультфильмов." TEST_WELCOME = "Пройди следующий короткий тест, чтобы было легче подобрать тебе пару. А еще ты узнаешь, кто ты из <b>героев славянских мифов.</b>"
TEST_RESULT = "Ты - {}!\n\n{}" TEST_RESULT = "👉 Ты - {}!👈\n\n{}"
TEST_FINISH = "Поздравляем! Теперь вы зарегистрированы в системе." TEST_FINISH = "🎉 Поздравляем! 🎉" "\nТеперь вы зарегистрированы в системе."
TEST_QUESTIONS = [ TEST_QUESTIONS = [
{ {
"question": "Когда вы оказываетесь в новой компании людей, вы, как правило:", "question": "На кого из героев славянских мифов вы хотели бы быть похожи?",
"answers": [ "answers": [
( {
"Легко заводите разговоры с разными людьми.", "text": "<u><b>На Перуна — защищать порядок, брать ответственность и вести других за собой ✊🏻</b></u>.",
"E", "types": ["ENTJ"],
), "short": "Перун!",
( },
"Предпочитаете сначала понаблюдать и только потом начать общаться с теми, кто вам интересен.", {
"I", "text": "<u><b>На Велеса — искать скрытые знания и понимать тайны мира 🔮</b></u>.",
), "types": ["INTP"],
"short": "Велес!",
},
{
"text": "<u><b>На Морену — видеть глубинные смыслы и управлять переменами 🪬</b></u>.",
"types": ["INFJ"],
"short": "Морена!",
},
{
"text": "<u><b>На Стрибога — быть свободным, приносить новые идеи и перемены 😌</b></u>.",
"types": ["ENTP"],
"short": "Стрибог!",
},
{
"text": "<u><b>На Ладу — создавать гармонию и помогать людям находить общий язык ☺️</b></u>.",
"types": ["ESFJ"],
"short": "Лада!",
},
{
"text": "<u><b>На Макошь — заботиться о судьбах других и поддерживать близких 🫂</b></u>.",
"types": ["ISFJ"],
"short": "Макошь!",
},
{
"text": "<u><b>На Ярило — жить ярко, действовать смело и наслаждаться моментом 😏</b></u>.",
"types": ["ESTP"],
"short": "Ярило!",
},
{
"text": "<u><b>На Домового — защищать свой мир и сохранять стабильность 💪🏻</b></u>.",
"types": ["ISTJ"],
"short": "Домовой!",
},
{
"text": "<u><b>На Чернобога — видеть стратегию и действовать по своему плану 😎</b></u>.",
"types": ["INTJ"],
"short": "Чернобог!",
},
{
"text": "<u><b>На Купалу — вдохновлять других и приносить радость 🤩</b></u>.",
"types": ["ENFP"],
"short": "Купала!",
},
{
"text": "<u><b>На Даждьбога — помогать людям расти и вести их к свету 🤗</b></u>.",
"types": ["ENFJ"],
"short": "Даждьбог!",
},
{
"text": "<u><b>На Живу — жить в гармонии с собой и чувствовать мир 😇</b></u>.",
"types": ["ISFP"],
"short": "Жива!",
},
{
"text": "<u><b>На Кощея — быть независимым и полагаться только на себя 😉</b></u>.",
"types": ["ISTP"],
"short": "Кощей!",
},
{
"text": "<u><b>На Рода — создавать основы и поддерживать порядок мира 🙌🏻</b></u>.",
"types": ["ESTJ"],
"short": "Род!",
},
{
"text": "<u><b>На Лелю — верить в добро и следовать своему сердцу 🫶🏻</b></u>.",
"types": ["INFP"],
"short": "Леля!",
},
{
"text": "<u><b>На Жар-птицу — зажигать сердца и превращать жизнь в яркое приключение 🔥</b></u>.",
"types": ["ESFP"],
"short": "Жар-птица!",
},
], ],
}, },
{ {
"question": "Вы пишете книгу или создаете проект. Какой подход вам ближе?", "question": "На работе вам важнее всего:",
"answers": [ "answers": [
( {
"Тщательно исследую тему, соберу всю доступную информацию и буду двигаться шаг за шагом, основываясь на фактах.", "text": "Возможность творить и воплощать самые безумные идеи 😜.",
"S", "types": ["ENFP", "ENTP", "INFP", "INTP"],
), "short": "Творчество!",
( },
"Сначала придумаю общую концепцию, представлю мир и героев (или цели проекта), и буду импровизировать, раскрывая детали по ходу дела.", {
"N", "text": "Профессиональный рост и постоянный апгрейд навыков 😌",
), "types": ["ENTJ", "ESTJ", "ISTJ", "ISFJ"],
"short": "Карьера!",
},
], ],
}, },
{ {
"question": "Ваш друг совершил ошибку, которая имеет серьезные последствия. Как вы отреагируете?", "question": "В дружбе вы цените больше всего:",
"answers": [ "answers": [
( {
"Объективно проанализирую ситуацию, укажу на ошибки и предложу логичное решение проблемы.", "text": "Позитивное мышление и фонтаны идей. Когда друг звонит ночью и предлагает сделать из картона ракету, чтобы улететь на Марс, я уже ищу скотч 👀",
"T", "types": ["ENFP", "ENTP", "ESFP", "ESTP"],
), "short": "Идеи!",
( },
"Постараюсь понять его мотивы, проявить сочувствие и оказать эмоциональную поддержку, чтобы он справился с ситуацией.", {
"F", "text": "Искренность. Вы знаете о друге всё: почему он не любит лук, сколько хомяков загубил в детстве и какую песню пел на выпускном 🫶🏻",
), "types": ["INFJ", "INFP", "ISFJ", "INTJ"],
"short": "Искренность!",
},
], ],
}, },
{ {
"question": "Представьте, что у вас есть свободный день. Что вы выберете?", "question": "Что вас вдохновляет?",
"answers": [ "answers": [
( {
"Заранее составлю план, чтобы максимально эффективно использовать время: посетить музей, заняться спортом, встретиться с друзьями.", "text": "Галочка напротив выполненного дела и зачеркнутые пункты в плане ✅",
"J", "types": ["ENTJ", "ESTJ", "ISTJ", "INTJ"],
), "short": "Планирование!",
( },
"Отложу все планы и позволю дню разворачиваться спонтанно: почитаю книгу, прогуляюсь по парку или просто буду наслаждаться моментом.", {
"P", "text": "Душевные разговоры, после которых хочется обнимать весь мир 🫂",
), "types": ["ENFJ", "INFJ", "ISFP", "INFP"],
"short": "Душевность!",
},
], ],
}, },
] ]
TEST_RESULTS = { TEST_RESULTS = {
"INTJ": ( "INTJ": (
"Профессор Селезнёв", "Чернобог",
"Ты умеешь воспринимать ситуацию глобально, а твои действия точны и эффективны. Ты, как и профессор Селезнев, привык к системному подходу и логическому анализу, эксперт в своей области", "Ты стратег, как Чернобог. Умеешь видеть общую картину и планировать наперёд. Ты действуешь точно и уверенно, опираясь на разум.",
), ),
"INTP": ( "INTP": (
"Знайка", "Велес",
"Знаешь всё про всё и даже больше. Предпочитаешь полагаться на свою голову. Любишь “покопаться” в каком-нибудь вопросе и не боишься выдвигать даже самые неожиданные гипотезы", "Ты мудрый искатель истины, как Велес — хранитель тайных знаний. Ты стремишься понять мир глубже и видишь то, что скрыто от других. Твоя сила в интеллекте и наблюдательности.",
), ),
"INFJ": ( "INFJ": (
"Ёжик в тумане", "Морена",
"Ты, как и Ежик, типичный интроверт, погруженный в свой внутренний мир. Ты глубоко чувствуешь окружающий мир и обладаешь богатым воображением. Хоть и бываешь застенчив и раним, но при этом ты отзывчив и добр.", "Ты загадочная и глубокая личность, как Морена. Чувствуешь перемены и понимаешь истинную природу вещей. Твоя мудрость помогает тебе видеть то, что недоступно другим.",
), ),
"INFP": ( "INFP": (
"Кот Леопольд", "Леля",
"«Ребята, давайте жить дружно!». Ты стремишься к гармонии во всех сферах жизни. Ты творческая личность, которая в принятии решений руководствуется своими ценностями и убеждениями", "Ты чистая и искренняя душа, как Леля. Веришь в добро и следуешь своему сердцу. Твоя сила в чувствах и внутренней правде.",
), ),
"ISTJ": ( "ISTJ": (
"Кролик из Винни Пуха", "Домовой",
"“-И это всё потому, что у кого-то очень узкие двери! -Нет! Это всё потому, что кто-то слишком много ест!” Ты, как и кролик, всегда логичен и прагматичен. Не тратишь слов попусту, но в ответ на критику за словом в карман не полезешь))", "Ты надёжный защитник, как Домовой. Ценишь порядок, стабильность и безопасность. На тебя всегда можно положиться.",
), ),
"ISTP": ( "ISTP": (
"Буратино", "Кощей",
"Ты стремишься узнать мир и найти свое место в жизни. Ты, как и Буратино, полон энергии и любопытства. Ты всегда готов исследовать новое и пробовать разные вещи", "Ты независимый и сильный, как Кощей. Привык полагаться на себя, умеешь выживать и находить решения в любой ситуации.",
), ),
"ISFJ": ( "ISFJ": (
"Пятачок", "Макошь",
"Ты добрый и заботливый (поросенок), всегда готов поддержать своих друзей. Любишь проявлять преданность и стремление заботиться о других, стараясь сделать их счастливыми. Как и Пятачок ты всегда готов прийти на помощь, даже если это требует смелости.", "Ты хранитель судьбы, как Макошь. Заботишься о других и создаёшь стабильность. Люди доверяют тебе и чувствуют рядом с тобой безопасность.",
), ),
"ISFP": ( "ISFP": (
"Кот Матроскин", "Жива",
"Ты гибкий, очаровательный артист, всегда готовый исследовать и испытать что-то новое. Ты творческая личность, тонкая, эмоциональные и чувствительные натура", "Ты живёшь в гармонии, как богиня Жива. Тонко чувствуешь мир и ценишь красоту. Твоя сила — в искренности и внутреннем балансе.",
), ),
"ENTJ": ( "ENTJ": (
"Сыщик из бременских музыкантов", "Перун",
"Оу ес! Ты решителен и успешен в любом деле. Можешь легко подстроиться под обстоятельства и наперёд просчитать свои действия, прямо как гениальный сыщик!", "Ты прирождённый лидер, как Перун — бог грома и справедливости. Ты берёшь ответственность на себя и уверенно ведёшь других. Твоя сила в решительности, порядке и способности действовать без колебаний.",
), ),
"ENTP": ( "ENTP": (
"Карлсон", "Стрибог",
"“В самом расцвете сил!” Ты экстравертен, обаятелен, остроумен, любишь привлекать внимание и постоянно придумывать новые затеи!", "Ты свободный дух, как Стрибог — бог ветра. Ты приносишь новые идеи и перемены. Твоя энергия вдохновляет и открывает новые возможности.",
), ),
"ENFJ": ( "ENFJ": (
"Почтальон Печкин", "Даждьбог",
"Своей яркой харизмой ты без усилий убеждаешь и увлекаешь других, наполняя пространство теплом и создавая отличную атмосферу для продуктивной работы.", "Ты несёшь свет и развитие, как Даждьбог. Ты вдохновляешь других и помогаешь им становиться лучше. Твоя сила в поддержке и лидерстве.",
), ),
"ENFP": ( "ENFP": (
"Трубадур из бременских музыкантов", "Купала",
"Ты энергичный, харизматичный и независимый человек. Ты не боишься перемен и всегда открыт к чему-то новому, легко находишь общий язык с людьми, а твое творческое мышление помогает находить нестандартные решения", "Ты приносишь радость и вдохновение, как Купала. Любишь жизнь, новые эмоции и возможности. Люди тянутся к твоему свету.",
), ),
"ESTJ": ( "ESTJ": (
"Римма Трофимовна. Мама дядя Федора", "Род",
"Ты являешься практичным и инициативным человеком, способным организовывать своё время и задачи. Высокие стандарты, которые ты установил для себя, делают тебя надежным и вдохновляющим примером для окружающих.", "Ты создаёшь основы, как Род — создатель мира. Ты организованный и ответственный. Ты умеешь строить порядок и управлять процессами.",
), ),
"ESTP": ( "ESTP": (
"Волк из “Ну, погоди!”", "Ярило",
"Ты энергичный, авантюрный и предприимчивый. Как Волк всегда стремишься достичь своей цели и, не останавливаясь, ищешь новых приключений!", "Яркость и смелость, как у Ярило — бога солнца и жизни. Ты любишь действовать и не боишься риска. Ты живёшь настоящим моментом.",
), ),
"ESFJ": ( "ESFJ": (
"Дядя Федор", "Лада",
"Как и Дядя Федор, ты надежный и ответственный, на тебя всегда можно положиться. Ты внимателен к потребностям и чувствам других людей и всегда готов прийти на помощь.", "Ты создаёшь гармонию, как богиня Лада. Умеешь объединять людей и заботиться о них. Твоя сила в доброте, поддержке и способности создавать баланс.",
), ),
"ESFP": ( "ESFP": (
"Мышонок (“Какой чудесный день, какой чудесный пень…”)", "Жар-птица",
"Заводила, запевала. Всегда в центре событий. Умеешь заставить улыбнуться людей", "Ты — огонь праздника, как Жар-птица. Умеешь зажигать людей вокруг, любишь яркие впечатления и легко превращаешь обычный день в событие. Твоя сила в харизме, смелости и умении жить “здесь и сейчас”.",
), ),
} }
Regular → Executable
+37 -11
View File
@@ -2,7 +2,7 @@ from db import DB
from plugin.bot_instance import bot from plugin.bot_instance import bot
from config import Messages from config import Messages
from telebot import types from telebot import types
from typing import List, Tuple from typing import List
users_reg: List["User"] = [] users_reg: List["User"] = []
@@ -10,7 +10,7 @@ users_reg: List["User"] = []
class User: class User:
_db = DB("Users") _db = DB("Users")
def __init__(self, user_id, name): def __init__(self, user_id, name=None):
self.user_id: int = user_id self.user_id: int = user_id
self._name: str = name self._name: str = name
self._age: int = None self._age: int = None
@@ -18,11 +18,9 @@ class User:
self._faculty: str = None self._faculty: str = None
self._group: str = None self._group: str = None
self._type: str = None self._type: str = None
self._agree_upload: bool = None
self._vector_type: dict = None
self._save()
def __init__(self, user_id):
self.user_id: int = user_id
self._load() self._load()
@property @property
@@ -91,6 +89,28 @@ class User:
return self._type return self._type
@property
def agree_upload(self):
return self._agree_upload
@agree_upload.setter
def agree_upload(self, value):
self._agree_upload = value
self.update_data()
return self._agree_upload
@property
def vector_type(self):
return self._vector_type
@vector_type.setter
def vector_type(self, value):
self._vector_type = value
self.update_data()
return self._vector_type
def _into_json(self): def _into_json(self):
return { return {
"_id": self.user_id, "_id": self.user_id,
@@ -100,6 +120,8 @@ class User:
"faculty": self._faculty, "faculty": self._faculty,
"group": self._group, "group": self._group,
"type": self._type, "type": self._type,
"agree_upload": self._agree_upload,
"vector_type": self._vector_type,
} }
def update_data(self): def update_data(self):
@@ -121,7 +143,8 @@ class User:
def _load(self): def _load(self):
if not self._db.exist({"_id": self.user_id}): if not self._db.exist({"_id": self.user_id}):
raise ValueError("User not found") self._save()
# raise ValueError("User not found")
data = self._db.find_one({"_id": self.user_id}) data = self._db.find_one({"_id": self.user_id})
self._name = data["name"] self._name = data["name"]
@@ -131,11 +154,13 @@ class User:
self._faculty = data["faculty"] self._faculty = data["faculty"]
self._group = data["group"] self._group = data["group"]
self._type = data["type"] self._type = data["type"]
self._agree_upload = data["agree_upload"]
self._vector_type = data["vector_type"]
@staticmethod @staticmethod
def start_shuffle_reg(): def start_shuffle_reg():
users_reg.clear() users_reg.clear()
users = [user for user in User.get_all() if user.type] users = [user for user in User.get_all() if (user.type and len(user.type) == 4)]
markup = types.InlineKeyboardMarkup() markup = types.InlineKeyboardMarkup()
markup.add( markup.add(
@@ -145,22 +170,23 @@ class User:
for user in users: for user in users:
bot.send_message(user.user_id, Messages.MATCHING_START, reply_markup=markup) bot.send_message(user.user_id, Messages.MATCHING_START, reply_markup=markup)
return
@staticmethod
@bot.callback_query_handler(func=lambda call: call.data == "shuffle_agree") @bot.callback_query_handler(func=lambda call: call.data == "shuffle_agree")
def add_user_to_reg(call: types.CallbackQuery): def add_user_to_reg(call: types.CallbackQuery):
user = User(call.message.chat.id) user = User(call.message.chat.id)
users_reg.append(user) users_reg.append(user)
bot.edit_message_text( bot.edit_message_text(
"Вы добавлены в список участников! Пожалуйста, подождите, пока все зарегистрируются",
call.message.chat.id, call.message.chat.id,
call.message.message_id, call.message.message_id,
"Вы добавлены в список участников! Пожалуйста, подождите, пока все зарегистрируются",
reply_markup=None, reply_markup=None,
) )
return return
return
def __str__(self): def __str__(self):
text = [f"{var}: {vars(self)[var]}" for var in vars(self) if var] text = [f"{var}: {vars(self)[var]}" for var in vars(self) if var]
text = "\n".join(text) text = "\n".join(text)
Regular → Executable
View File
Regular → Executable
+7 -16
View File
@@ -1,32 +1,23 @@
version: '3.8'
services: services:
bot: bot:
image: python:3.9 image: python:3.9
container_name: python_bot container_name: python_bot
working_dir: /usr/src/app working_dir: /usr/src/app
links:
- "mongodb:mongo"
volumes: volumes:
- ./app:/usr/src/app - ./app:/usr/src/app
networks:
- rc_network
depends_on: depends_on:
- mongodb - mongodb
command: sh -c "pip install -r requirements.txt && python main.py" command: sh -c "pip install -r requirements.txt && python -u main.py"
restart: unless-stopped
mongodb: mongodb:
image: mongo:latest image: 'mongo:4.4.6'
# image: mongo:8.0-rc
container_name: mongodb
networks:
- rc_network
volumes: volumes:
- mongo-data:/data/db - 'mongo-data:/data/db'
networks: restart: unless-stopped
rc_network:
driver: bridge
ipam:
config:
- subnet: 172.25.0.0/16
volumes: volumes:
mongo-data: mongo-data:
Regular → Executable
+3 -1
View File
@@ -5,6 +5,7 @@
## Запуск ## Запуск
1. Создать [файл .env](#env) в директории `app` 1. Создать [файл .env](#env) в директории `app`
- Пример файла расположен в корне (`.env.example`)
2. Запустить контейнеры с помощью docker compose: 2. Запустить контейнеры с помощью docker compose:
- `docker-compose up -d` - `docker-compose up -d`
@@ -46,6 +47,7 @@
- `/random_again` - сгенерировать повторную рассадку для людей первого тура (без повторной регистрации) - `/random_again` - сгенерировать повторную рассадку для людей первого тура (без повторной регистрации)
- `/clear_all` - удалить всех людей из базы данных - `/clear_all` - удалить всех людей из базы данных
- `/remove_admin` - удалить админа по id - `/remove_admin` - удалить админа по id
- `/restart` - перезапуск бота (только для Docker запуска)
## <a id="env">Настройка конфигурации</a> ## <a id="env">Настройка конфигурации</a>
@@ -56,7 +58,7 @@
- `API_TOKEN` - токен для tg бота полученный у `@BotFather` - `API_TOKEN` - токен для tg бота полученный у `@BotFather`
- `ADMIN_ID` - id **_главного админа_** - `ADMIN_ID` - id **_главного админа_**
- `DB_PORT` порт для MongoDB, стандартно `27017` - `DB_PORT` порт для MongoDB, стандартно `27017`
- `ENV` - если выставлен как `dev`: - `ENV` - если выставлен как `DEV`:
- возможность подключаться к базе данных удалённо через SSH - возможность подключаться к базе данных удалённо через SSH
- `SSH_HOST` - имя/ip хоста - `SSH_HOST` - имя/ip хоста
- `SSH_USER` - имя пользователя - `SSH_USER` - имя пользователя