From c0c10af93716dae35f4c3afe9bdac415df7341f2 Mon Sep 17 00:00:00 2001 From: Artem Reznichenko Date: Wed, 29 Nov 2023 12:32:23 +0300 Subject: [PATCH] another one --- bot/app/bot.py | 140 ++++++++++++++++++++++++++++++++++++++++---- bot/app/textbook.py | 11 +++- 2 files changed, 139 insertions(+), 12 deletions(-) diff --git a/bot/app/bot.py b/bot/app/bot.py index 9555e97..99632a1 100644 --- a/bot/app/bot.py +++ b/bot/app/bot.py @@ -26,6 +26,7 @@ import keyboards # DB from db.base import Session, engine, Base from db.models import User, Group, GroupMember, Fund, FundMember +from sqlalchemy.orm import joinedload bot = AsyncTeleBot(token, state_storage=StatePickleStorage()) @@ -35,6 +36,7 @@ session: Session = None class States(StatesGroup): default = State() newfund_amount = State() + newfund_description = State() close_fund = State() @@ -49,6 +51,7 @@ def get_fund_text(fund: Fund): active="🟢" if fund.active else "🔴", name=fund.name, amount=fund.amount, + description=fund.description, personal_amount=personal_amount, collected_amount=personal_amount * contributors, contributors=contributors, @@ -87,9 +90,16 @@ def get_group(tg_chat: TgChat) -> Group: async def start(msg: Message): if msg.chat.type == "private": user = get_user(msg.from_user) + fund_members_count = ( + session.query(FundMember) + .join(Fund) + .filter(Fund.owner_id == user.id, Fund.active == True) + .options(joinedload(FundMember.fund)) + .count() + ) await bot.send_message( chat_id=msg.chat.id, - text=textbook.start_private.format(count=user.fund_members.count()), + text=textbook.start_private.format(count=fund_members_count), ) elif msg.chat.type in ("group", "supergroup"): @@ -183,22 +193,64 @@ async def cancel_newfund_amount(call: types.CallbackQuery): ) +@bot.callback_query_handler( + func=lambda c: c.data == "cancel", state=States.newfund_description +) +async def cancel_newfund_description(call: types.CallbackQuery): + await bot.set_state( + user_id=call.from_user.id, chat_id=call.message.chat.id, state=States.default + ) + await bot.delete_message(chat_id=call.message.chat.id, message_id=call.message.id) + await bot.answer_callback_query( + callback_query_id=call.id, + text=textbook.cancel, + ) + + @bot.message_handler(content_types=["text"], state=States.newfund_amount) async def newfund_amount(msg: Message): - if not session.query(User).filter(User.id == msg.from_user.id).first(): - user = User( - id=msg.from_user.id, - name=msg.from_user.first_name, - username=msg.from_user.username, - ) - session.add(user) - session.commit() if msg.text.isdigit(): + async with bot.retrieve_data( + user_id=msg.from_user.id, chat_id=msg.chat.id + ) as state_data: + state_data["newfund_amount"] = int(msg.text) + await bot.set_state( + user_id=msg.from_user.id, + chat_id=msg.chat.id, + state=States.newfund_description, + ) + await bot.send_message( + chat_id=msg.chat.id, + text=textbook.newfund_description, + reply_markup=keyboards.cancel(), + parse_mode="html", + ) + + else: + await bot.send_message( + chat_id=msg.chat.id, + text=textbook.not_number.format(user=user_link(msg.from_user)), + reply_markup=keyboards.cancel(), + parse_mode="html", + ) + + +@bot.message_handler(content_types=["text"], state=States.newfund_description) +async def newfund_description(msg: Message): + if len(msg.text) < 121: await bot.set_state( user_id=msg.from_user.id, chat_id=msg.chat.id, state=States.default ) + async with bot.retrieve_data( + user_id=msg.from_user.id, chat_id=msg.chat.id + ) as state_data: + amount = state_data.get("newfund_amount") fund = Fund( - owner_id=msg.from_user.id, group_id=msg.chat.id, amount=int(msg.text) + owner_id=msg.from_user.id, + group_id=msg.chat.id, + description=msg.text, + amount=amount, + name=datetime.today().strftime("%d.%m"), ) session.add(fund) for group_member in session.query(GroupMember).filter( @@ -222,7 +274,7 @@ async def newfund_amount(msg: Message): else: await bot.send_message( chat_id=msg.chat.id, - text=textbook.not_number.format(user=user_link(msg.from_user)), + text=textbook.newfund_description_too_long, reply_markup=keyboards.cancel(), parse_mode="html", ) @@ -411,6 +463,72 @@ async def remind(msg: Message): ) +@bot.message_handler(commands=["dmremind"]) +async def dmremind(msg: Message): + if msg.chat.type in ("group", "supergroup"): + group = get_group(msg.chat) + if ( + fund := session.query(Fund) + .filter(Fund.group_id == group.id, Fund.active == True) + .first() + ): + not_contributed = fund.members.filter(FundMember.contributed == False).all() + if len(not_contributed): + counter = 0 + not_sent = [] + for member in not_contributed: + try: + await asyncio.sleep(0.1) + await bot.send_message( + chat_id=member.user.id, + text=textbook.dmremind.format( + fund_name=fund.name, chat_name=msg.chat.title + ), + ) + counter += 1 + except Exception: + not_sent.append(member) + s = textbook.dmremind_completed.format( + sent_count=counter, members_count=len(not_contributed) + ) + + if not_sent: + s += "\n" + textbook.dmremind_not_sent_list.format( + members=", ".join([m.user.name for m in not_sent]) + ) + await bot.send_message( + chat_id=msg.chat.id, + text=s, + parse_mode="html", + ) + else: + await bot.send_message( + chat_id=msg.chat.id, + text=textbook.remind_already.format(fund_name=fund.name), + parse_mode="html", + ) + else: + await bot.send_message( + chat_id=msg.chat.id, + text=textbook.fund_not_found, + ) + + +@bot.message_handler(commands=["setup_list"]) +async def setup_list(msg: Message): + if msg.chat.type in ("group", "supergroup"): + group = get_group(msg.chat) + members = group.group_members + await bot.send_message( + chat_id=msg.chat.id, + text=textbook.setup_list.format( + count=members.count(), + members=", ".join(m.user.name for m in members.all()), + ), + parse_mode="html", + ) + + @bot.message_handler(commands=["mystate"]) async def mystate(msg: Message): state = await bot.get_state(user_id=msg.from_user.id) diff --git a/bot/app/textbook.py b/bot/app/textbook.py index 65fc9b1..433a798 100644 --- a/bot/app/textbook.py +++ b/bot/app/textbook.py @@ -10,6 +10,10 @@ user_left = "Вы отказались от участия в сборах в э newfund_already_exists = "Предыдущий сбор все еще активен! Пропишите /fund, чтобы показать его, и завершите его, если необходимо создать новый!" newfund_amount = 'Отлично, новый сбор. {user}, напишите сумму сбора ответом на это сообщение, или нажмите кнопку "❌ Отменить"' +newfund_description = "Хорошо, теперь напишите описание сбора ответом на это сообщение (не более 120 символов). Это может быть номер или ссылка куда кидать деньги, к примеру." +newfund_description_too_long = ( + "Слишком длинное описание, лимит - 120 символов, попробуйте еще раз!" +) cancel = "Хорошо, проехали" not_number = 'Вы ввели не число. {user}, напишите сумму сбора ответом на это сообщение, или нажмите кнопку "❌ Отменить"' fund_created = "Создан новый сбор: {fund}" @@ -17,7 +21,7 @@ fund_created = "Создан новый сбор: {fund}" fund_not_found = "На данный момент в этом чате сборов нет! Создать новый - /newfund" -fund = "{active} {name}\n\n💵 Сумма: {amount}р\n\nКаждый скидывает по {personal_amount}р\nУже собрано: {collected_amount}р\n👥 Скинули: {contributors}/{count} чел." +fund = "{active} {name}\n\n💵 Сумма сбора: {amount}р\n\n{description}\n\nКаждый скидывает по {personal_amount}р\nУже собрано: {collected_amount}р\n👥 Скинули: {contributors}/{count} чел." close_fund_prompt = "Вы уверены? Это завершит активный в данный момент сбор!" fund_closed = 'Сбор "{name}" закрыт! Вот его данные:\n\n{fund_text}' @@ -33,3 +37,8 @@ remind_already = "На сбор {fund_name} уже все скинули fund_completed = ( "Сбор {fund_name} завершен, поздравляю всех, и в особенности {owner_str} 🎉" ) +dmremind = "Ты забыл(а) скинуться на {fund_name} в чате {chat_name}!" +dmremind_completed = "Сообщение разослано {sent_count} из {members_count} юзерам!" +dmremind_not_sent_list = "Не получилось разослать юзерам:\n\n{members}\n\nМожешь написать им в личку сам(а)? Они забыли активировать меня в лс(" + +setup_list = "В сборах в этом чате сейчас участвует {count} человек. Вот они, слева направо:\n\n{members}\n\nДля добавления новых пропишите /setup и нажмите на кнопочку"