From 907adc6fd090c467aa3e80d64aac1126d0a436c3 Mon Sep 17 00:00:00 2001 From: ennucore Date: Mon, 20 Jun 2022 20:01:28 +0300 Subject: [PATCH] User polling and matching functions --- bot.py | 28 +++++++++++++++++++++++++++- community.py | 34 ++++++++++++++++++++++++++++++---- templates.txt | 10 ++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/bot.py b/bot.py index 66e7423..1f7514b 100644 --- a/bot.py +++ b/bot.py @@ -1,3 +1,5 @@ +import datetime + import telebot import pymongo from functools import wraps @@ -66,7 +68,8 @@ class Bot(telebot.TeleBot): as_reply: bool = False, locale_overwrite: typing.Optional[str] = None, **kwargs): if isinstance(msg, telebot.types.CallbackQuery): msg = msg.message - text, keyboard = self.render_message_for_user(self.get_user_by_msg(msg), template, + user = self.get_user_by_msg(msg) + text, keyboard = self.render_message_for_user(user, template, tg_user=msg.from_user, locale_overwrite=locale_overwrite, **kwargs) if as_reply: @@ -74,6 +77,14 @@ class Bot(telebot.TeleBot): else: self.send_message(msg.chat.id, text, reply_markup=keyboard, parse_mode='HTML') + def send_template(self, user_id: int, template: str, locale_overwrite: typing.Optional[str] = None, **kwargs): + user = User.by_id(user_id, self) + tg_user = self.get_chat(user_id) + text, keyboard = self.render_message_for_user(user, template, + tg_user=tg_user, locale_overwrite=locale_overwrite, + **kwargs) + self.send_message(user_id, text, reply_markup=keyboard, parse_mode='HTML') + def get_user_from_db(self, request: dict) -> typing.Optional[User]: data = self.db.users.find_one(request) if data is None: @@ -175,6 +186,21 @@ class Bot(telebot.TeleBot): for user_data in self.db.users.find(): yield User.from_dict(user_data) + def iter_communities(self) -> typing.Iterable[Community]: + for community_data in self.db.communities.find(): + yield Community.from_dict(community_data) + + def poll_users_in_community(self, community: Community): + for user_id in community.users_to_poll(): + user = User.by_id(user_id, self) + if user is None: + continue + def_answer = community.default_answers.get(user_id, True) + self.send_template(user_id, 'poll_user', community=community, def_answer=def_answer) + community.pool += [user_id] * def_answer + community.polled[user_id] = datetime.date.today() + self.save_community(community) + def register_next_step_handler(self, message, callback, *args, **kwargs): if isinstance(message, telebot.types.CallbackQuery): message = message.message diff --git a/community.py b/community.py index 1f43c2d..09afc7f 100644 --- a/community.py +++ b/community.py @@ -1,7 +1,8 @@ from __future__ import annotations from dataclasses import dataclass, field, asdict import typing -from datetime import date +import random +from datetime import date, timedelta from telebot.types import ChatMember, Chat import time from threading import Thread @@ -15,10 +16,12 @@ class Community: chat_id: int # Telegram chat id name: str = '' members: typing.List[int] = field(default_factory=list) - pool: typing.List[typing.Tuple[int, int]] = field(default_factory=list) # (user_id, number_of_copies) + pool: typing.List[int] = field(default_factory=list) # [user_id] + polled: typing.Dict[int, date] = field(default_factory=dict) # Days since the user was asked scheduled_meetings: typing.List[typing.Tuple[int, int, date]] = field( default_factory=list) # (user_id_1, user_id_2, meeting date) archived_meetings: typing.List[typing.Tuple[int, int, date]] = field(default_factory=list) + default_answers: typing.Dict[int, bool] = field(default_factory=dict) # Last answers start_timestamp: int = field(default_factory=lambda: int(time.time())) def dict(self) -> dict: @@ -29,8 +32,8 @@ class Community: def from_dict(cls, data: dict) -> Community: data = getattr(data, '__dict__', data) data_ = {key: data[key] for key in data.keys() if - key in ['chat_id', 'name', 'members', 'pool', 'scheduled_meetings', 'archived_meetings', - 'start_timestamp']} + key in ['chat_id', 'name', 'members', 'pool', 'polled', 'scheduled_meetings', + 'archived_meetings', 'start_timestamp', 'default_answers']} self = cls(**data_) return self @@ -55,3 +58,26 @@ class Community: bot.save_community(self) return True return False + + def users_to_poll(self) -> typing.List[int]: + return [ + user_id for user_id in self.members + if user_id not in self.polled or self.polled[user_id] <= date.today() - timedelta(days=7) + ] + + def add_answer(self, user_id: int, answer: bool, bot: Bot): + if user_id not in self.users_to_poll(): + return + self.pool.remove(user_id) + self.pool += [user_id] * answer + self.default_answers[user_id] = bool(answer) + bot.save_community(self) + + def schedule_meetings(self): + random.shuffle(self.pool) # It's called RandomTea for a reason + today = date.today() + while len(self.pool) > 1: + user_id_1 = self.pool.pop() + while (user_id_2 := self.pool.pop()) == user_id_1: + continue + self.scheduled_meetings.append((user_id_1, user_id_2, today)) diff --git a/templates.txt b/templates.txt index 1bbf197..4337d70 100644 --- a/templates.txt +++ b/templates.txt @@ -35,6 +35,16 @@ You have joined the community, congrats! //| ru |// Вы присоединились к сообществу, хорошего дня! +||<| poll_user |>|| +//| en |// +Do you want to have any meetings this week{% if community.name %} in the community {{ community.name }}{% endif %}? +>>| {{ "✅" * bool(def_answer) }} Yes :-: meetings_{{ community.chat_id }}_1 |<< +>>| {{ "✅" * (not def_answer) }} No :-: meetings_{{ community.chat_id }}_0 |<< +//| ru |// +Хотите ли вы сходить на встречи на этой неделе{% if community.name %} в сообществе {{ community.name }}{% endif %}? +>>| {{ "✅" * bool(def_answer) }} Да :-: meetings_{{ community.chat_id }}_1 |<< +>>| {{ "✅" * (not def_answer) }} Нет :-: meetings_{{ community.chat_id }}_0 |<< + ||<| canceled |>|| //| en |// Canceled