def on_mig_click(cls, bot: telegram.Bot, _: telegram.Message, query: telegram.CallbackQuery, data): uid = query.from_user.id card: Card = cache.get(cls.__get_key(data['card_id'])) if not card: bot.answer_callback_query( query.id, f"Ошибка. Не могу найти открытку #{data['card_id']}", show_alert=True) return if uid != card.to_uid: bot.answerCallbackQuery( query.id, 'Только адресат валентинки может подмигнуть 💔') return if uid in card.mig_uids: if User.get(uid).female: text = 'Подруга, ты уже подмигивала 💆' else: text = 'Дружище, ты уже подмигивал 💆♂️' bot.answerCallbackQuery(query.id, text) return card.mig_uids.append(uid) cache.set(cls.__get_key(card.card_id), card, time=USER_CACHE_EXPIRE) bot.answerCallbackQuery(query.id, 'Подмигивание прошло успешно') Stats.total_migs.incr() Stats.migs_users.add(uid) user = User.get(uid) username = user.get_username_or_link() ReactionNotification.send(bot, card.from_uid, f"{username} подмигивает тебе ❤", card) cls.__set_card_preview_as_done(bot, card)
def get_top_pair(uid: int) -> Optional[User]: replylove__dragon_lovers = CONFIG.get('replylove__dragon_lovers', []) if uid in replylove__dragon_lovers: return User(0, 0, 'drakon', '🐉') replylove__ignore = CONFIG.get('replylove__ignore', []) replylove__ignore_pairs = CONFIG.get('replylove__ignore_pairs', {}).get(str(chat_id), {}).get(str(uid), []) pairs: List[Tuple[str, int]] = sort_dict(db['pair']) for pair, count in pairs: a_uid, b_uid = [get_int(x) for x in pair.split(',')] strast = None if a_uid is None or b_uid is None: continue if count < 5: continue if uid == a_uid and a_uid == b_uid: continue if any(x in replylove__dragon_lovers for x in (a_uid, b_uid)): continue if any(x in replylove__ignore for x in (uid, a_uid, b_uid)): continue if any(x in replylove__ignore_pairs for x in (a_uid, b_uid)): continue if uid == a_uid: strast = User.get(b_uid) if uid == b_uid: strast = User.get(a_uid) if strast: return strast return None
def command_8(bot: telegram.Bot, update: telegram.Update) -> None: message: telegram.Message = update.message chat_id = message.chat_id from_uid = message.from_user.id if not can_use(chat_id, from_uid): send_limit(bot, chat_id) return if not is_day_active(): return all_uids = [chat_user.uid for chat_user in ChatUser.get_all(chat_id)] all_users = [User.get(uid) for uid in all_uids] males = [user.uid for user in all_users if not user.female] females = [user.uid for user in all_users if user.female] gifts = get_gifts() gift = random_uniq_for_chat(chat_id, gifts) result = random_gift_text(from_uid, males, females, gift, random.choice) from_user = User.get(result.from_uid) to_user = User.get(result.to_uid) text = result.text \ .replace('{from}', from_user.get_username_or_link()) \ .replace('{to}', to_user.get_username_or_link()) # reply_markup=get_reply_markup(answer.get_message_buttons()), bot.send_message(chat_id, text, parse_mode=telegram.ParseMode.HTML)
def check_valid(cls, text: str, uid: Optional[int]) -> ValidationResult: # нужно вычислить адресата to_username = cls.extract_username(text) if not to_username: return cls.ValidationResult( True, 'Через @username укажи кому отправлять валентинку') to_user = cls.find_user(to_username, CONFIG['anon_chat_id']) if not to_user: return cls.ValidationResult(True, f'В чате нет такого: {to_username}') # TODO: раскомментировать user = User.get(uid) if user and uid == to_user.uid: female = 'а' if user.female else '' return cls.ValidationResult(True, f'Сам{female} себе? Печально 😢') # проверочки if AntiPlagiat.is_plagiat(CONFIG['anon_chat_id'], text): return cls.ValidationResult( True, 'Ой! А такая валентиночка уже есть. Как неудобно…') # и если все хорошо return cls.ValidationResult(False, None, to_user.uid)
def show_personal_stat(self, user_id: int) -> str: def fun_word(word: str, fem: bool) -> str: if word == 'я': fem_a = 'а' if user.female else '' return f'я сосал{fem_a}' if word == 'меня': return 'меня ебали' if word == 'мне': return 'мне похуй' if word == 'мной': return 'мной восторгаются' if word == 'мною': return 'мною пренебрегают' return word user = User.get(user_id) if not user: raise Exception('User SHOULD be exist') stat = self.db.users.get(user_id, UserStat()) fem_a = 'а' if user.female else '' all_count = pytils.numeral.get_plural(stat.all_count, 'раз, раза, раз') msg_count = pytils.numeral.get_plural(getattr(stat, 'messages_count', 0), 'сообщении, сообщениях, сообщениях') header = f'{user.get_username_or_link()} говорил{fem_a} о себе {all_count} в {msg_count}.' c = Counter(stat.counts) body = '\n'.join((f'<b>{count}.</b> {fun_word(word, user.female)}' for word, count in c.most_common() if count > 0)) return f'{header}\n\n{body}'.strip()
def send_personal_stat(bot: telegram.Bot, chat_id: int, user_id: int, reply_to_message_id: Optional[int] = None) -> None: user = User.get(user_id) if not user: bot.send_message(chat_id, 'А кто это? Таких не знаю.', reply_to_message_id=reply_to_message_id) return show_data = extend_initial_data({ 'value': callback_show, 'chat_id': chat_id }) buttons = [ [('Показать мою стату', show_data)], ] reply_markup = get_reply_markup(buttons) rs = RedisChatStatistician(chat_id) rs.load() text = rs.chat_statistician.show_personal_stat(user_id) bot.send_message(chat_id, text, reply_to_message_id=reply_to_message_id, reply_markup=reply_markup, parse_mode=ParseMode.HTML)
def get_all_love_outbound(cls, chat_id: int, date=None, header='Вся исходящая страсть', no_love_show_only_count=False) -> str: all_chat_users = ChatUser.get_all(chat_id) all_users = (User.get(chatuser.uid) for chatuser in all_chat_users) all_users = sorted(all_users, key=lambda x: x.fullname) all_love = [(user, ReplyTop.get_user_top_strast(chat_id, user.uid, date)[2]) for user in all_users if user] in_love = [(a, b, ReplyTop.get_user_top_strast(chat_id, b.uid, date)[2]) for a, b in all_love if b] no_love = [a for a, b in all_love if not b] in_love_str = '\n'.join( cls.__format_pair(a, b, b_pair) for a, b, b_pair in in_love) if no_love_show_only_count is False: no_love_str = '' if len( no_love) == 0 else '\n\nБеcстрастные:\n' + '\n'.join( (cls.__format_pair(a) for a in no_love)) else: no_love_str = '' if len( no_love ) == 0 else f'\n\nИ еще {pytils.numeral.get_plural(len(no_love), "беcстрастный, беcстрастных, беcстрастных")}' return f'{header}:\n\n{in_love_str}{no_love_str}'
def __get_team(cls, chat_id: int) -> str: """ Возвращает строку с "коллективом" чата. Пример: "30 👨, 10 👩, 2 👘, 1 🍍, 2 🦆, 1 🐽, 3 🏳️🌈, 3 🐈, 4 🐕, 5 🐀" """ # Итоговая строка должна состоять из двух частей: # 1. количество мужчин/женщин (берется из настоящих данных) # 2. жестко зафиксированная "специальная часть" # нам нужно подсчитать количество людей, задействованных в спец части # и вычесть это количество из общего списка special = '2 👘, 1 🍍, 2 🦆, 1 🐽, 3 🏳️🌈, 3 🐈, 2 🐕, 5 🐀' special_count = 2 + 1 + 2 + 1 + 3 + 3 + 2 + 5 chat_users = ChatUser.get_all(chat_id) uids = [chat_user.uid for chat_user in chat_users ][:-special_count or None] # вычитаем # теперь нужно подсчитать сколько мужчин и женщин осталось users = (User.get(uid) for uid in uids) genders = ('👩' if user.female else '👨' for user in users if user) # noinspection PyArgumentList gender_counter = collections.Counter(genders) gender_text = ', '.join( (f'{count} {gender}' for gender, count in gender_counter.most_common())) # собираем итоговую строку return f'{gender_text}, {special}'.strip(',').strip()
def execute(self, bot: telegram.Bot): user = User.get(self.uid) old_text = cache.get( f'{CACHE_PREFIX}__message_text_{self.message_id}') if old_text: new_text = re.sub(r"^Подписано\s+[█ ]+$", f'Подписано {user.fullname}', old_text, 0, re.IGNORECASE | re.MULTILINE) buttons = cache.get( f'{CACHE_PREFIX}__message_buttons_{self.message_id}') reply_markup = self.get_reply_markup(buttons) female = 'а' if user.female else '' bot.send_message( FSBDayTelegram.chat_id, f'Какой ужас. Это был{female} {user.get_username_or_link()}', reply_to_message_id=self.message_id, parse_mode=telegram.ParseMode.HTML) return bot.edit_message_text( new_text, FSBDayTelegram.chat_id, self.message_id, parse_mode=telegram.ParseMode.HTML, reply_markup=reply_markup) bot.send_message( FSBDayTelegram.chat_id, f'Не могу исправить само сообщение. Но оно подписано {user.get_username_or_link()}', reply_to_message_id=self.message_id, parse_mode=telegram.ParseMode.HTML)
def auth_process(): data = request.get_json() if not data: abort(415) login = data.get("login", None) password = data.get("password", None) if not login or not password: return jsonify({"status": "fail", "message": "Вы должны ввести логин и пароль"}) try: user = User.get(User.login == login) except User.DoesNotExist: return jsonify({"status": "fail", "message": "Логин или пароль неправильные"}) rounds, password_hash, salt = parse_hashed_password(user.password) if hash_password(password, rounds, salt) != user.password: return jsonify({"status": "fail", "message": "Логин или пароль неправильные"}) safe_session = SafeSession.create(user=user, salt=generate_random_bytes_in_base64(32), session_key=generate_random_bytes_in_base64(32), session_expire=datetime.utcnow() + SESSION_ALIVE_TIME, client_ip=request.remote_addr) session["safe_id"] = safe_session.id session["safe_salt"] = safe_session.salt return jsonify({ "status": "ok", "sessionKey": safe_session.session_key, "userPrivateData": user.private_data, })
def get_top(type: str, uid: int) -> Optional[User]: if type not in db: return None if uid not in db[type]: return None replylove__ignore = CONFIG.get('replylove__ignore', []) if uid in replylove__ignore: return None replylove__dragon_lovers = CONFIG.get('replylove__dragon_lovers', []) if uid in replylove__dragon_lovers: return User(0, 0, 'drakon', '🐉') sorted: List[Tuple[int, int]] = sort_dict(db[type][uid]) if len(sorted) == 0: return None replylove__ignore_pairs = CONFIG.get('replylove__ignore_pairs', {}).get(str(chat_id), {}).get(str(uid), []) for result_uid, count in sorted: if count < 5: continue if uid == result_uid: continue if result_uid in replylove__dragon_lovers: continue if result_uid in replylove__ignore: continue if result_uid in replylove__ignore_pairs: continue return User.get(result_uid) return None
def get_private_data(): safe_session = get_safe_session() if not safe_session: return jsonify(__auth_error) user = User.get(User.id == safe_session.user_id) return jsonify({"status": "ok", "privateData": user.private_data})
def __get_header_text(cls, uid: int, header: str, small_spoiler: bool = False) -> str: user = User.get(uid) name = 'анонима' if not user else user.fullname small = 'Короткий спойлер' if small_spoiler else 'Спойлер' return f'<b>{small} от {name}</b>\n\n{header}'
def __format_uid(uid, show_username=True): user = User.get(uid) if not user: return '' username = '' if show_username and user.username is not None: username = f' @{user.username}' return f"<b>{user.fullname}</b>{username}".strip()
def edit(id): account = User.get(id=id) form = UserForm(obj=account) if form.validate_on_submit: account.set(**get_data(form)) flash('User updated') return redirect(url_for('user.show_all')) return render_template('/user/edit.html', form=form, account=account)
def __cant_send(cls, bot: telegram.Bot, chat_id: int, uid: int, spoiler_id: int) -> None: logger.info(f"[spoiler] {uid} can't show spoiler {spoiler_id}") user = User.get(uid) username = '' if not user else user.get_username_or_link() text = f'{username} Не могу отправить спойлер. Нажми Start в личке бота \ @{bot.username} и попробуй вновь' bot.send_message(chat_id, text, parse_mode=telegram.ParseMode.HTML)
def on_revn_click(cls, bot: telegram.Bot, _: telegram.Message, query: telegram.CallbackQuery, data) -> None: uid = query.from_user.id card: Card = cache.get(cls.__get_key(data['card_id'])) if not card: bot.answer_callback_query( query.id, f"Ошибка. Не могу найти открытку #{data['card_id']}", show_alert=True) return # уже ревновали? if uid in card.revn_uids: if User.get(uid).female: text = 'Подруга, да забудь ты про эту сучку 🍸' else: text = 'Дружище, да забей ты на эту сучку 🍺' bot.answerCallbackQuery(query.id, text) return card.revn_uids.append(uid) cache.set(cls.__get_key(card.card_id), card, time=USER_CACHE_EXPIRE) Stats.total_revn.incr() Stats.revn_users.add(uid) user = User.get(uid) if uid == card.to_uid: bot.answerCallbackQuery(query.id, 'Саша, ты? 👸') else: if user.female: text = 'Вот она сучка, да? Уж мы-то ей покажем 👗' else: text = 'Ха! Мы-то с тобой знаем, кто тут круче всех 👑' bot.answerCallbackQuery(query.id, text) username = user.get_username_or_link() to_username = '' if not User.get(card.to_uid) else User.get( card.to_uid).get_username_or_link() ReactionNotification.send(bot, card.to_uid, f"{username} ревнует к валентинке для тебя", card) ReactionNotification.send(bot, card.from_uid, f"{username} ревнует к {to_username}", card) cls.__update_buttons(bot, card)
def me_format_position(cls, username, group_msg_count, position, user_id): user = User.get(user_id) if not user: return f'Нет такого: {username}' uname = '{}'.format(user.get_username_or_link()) pos = '' if position != -1: pos = '{}. '.format(position) msg = '{2}{0} — {1}'.format(uname, group_msg_count, pos) return msg
def get_vuser(user_id: Optional[int]) -> Union[VUnknownUser, VChatsUser]: if user_id is None: return VUnknownUser() user = User.get(user_id) if user is None: return VUnknownUser(user_id) chats = {VChat(cid) for cid in get_user_chats(user_id)} return VChatsUser(user_id, chats, user.female)
def get_private_data(): safe_session = get_safe_session() if not safe_session: return jsonify(__auth_error) user = User.get(User.id == safe_session.user_id) return jsonify({ "status": "ok", "privateData": user.private_data })
def execute(self, bot): try: bot.send_message(self.uid, self.text, parse_mode=telegram.ParseMode.HTML, reply_to_message_id=self.reply_to_message_id) except: user = User.get(self.uid) logger.warning( f"[fsb_day] can't send message to {user.get_username_or_link()}" )
def __get_gender_stats(cls) -> str: uids = cls.senders.get() users = (User.get(uid) for uid in uids) genders = ('👩' if user.female else '👨' for user in users if user) # noinspection PyArgumentList gender_counter = collections.Counter(genders) gender_stats = ', '.join( (f'{count} {gender}' for gender, count in gender_counter.most_common())) text = f'Валентинки отправляли: {gender_stats}.' return text
def execute(self, bot): reply_markup = self.get_full_reply_markup(self.buttons) try: bot.send_message(self.uid, self.text, parse_mode=telegram.ParseMode.HTML, reply_markup=reply_markup) except: user = User.get(self.uid) logger.warning( f"[fsb_day] can't send message to {user.get_username_or_link()}" )
def find_user(username: Optional[str], chat_id: int) -> Optional[User]: if not username: return None uid = User.get_id_by_name(username) if not uid: return None chat_user = ChatUser.get(uid, chat_id) if not chat_user: return None if chat_user.left: return None return User.get(uid)
def get_chat_text(self): case_num = FSBDayCaseNumber() if case_num.title: header = f'<b>Дело № {case_num.num}.</b> <i>"{case_num.title}"</i>' else: header = f'<b>Дело № {case_num.num}</b>' random_user = User.get(ChatUser.get_random(CONFIG['anon_chat_id'])) user = User.get(self.uid) masked_sign = self.__mask_signature( random_user if random.randint(0, 100) < 70 else user) signature = f'Подписано {masked_sign}' if random_user else '' msg = lstrip_every_line( textwrap.dedent(f""" {header} {self.text} {signature} """)).strip() self.num = case_num.num return msg
def __super_stukach_alert( cls, uid: int) -> typing.Union[None, FSBDayTelegram.TelegramExecute]: recent_stucks = cache.get(f'{CACHE_PREFIX}__{uid}_recent_stucks') key_super_stukach_alert = f'{CACHE_PREFIX}__super_stukach_alert' if recent_stucks and recent_stucks >= 3 and not cache.get( key_super_stukach_alert): user = User.get(uid) cache.set(key_super_stukach_alert, True, time=30 * 60) return FSBDayTelegram.SendToChat( f'{user.get_username_or_link()} стучите помедленнее. Я не успеваю записывать.' ) return None
def send_mylove(bot: telegram.Bot, update: telegram.Update, send_to_cid: int, find_in_cid: int) -> None: def format_love(type: str, b: User, _: bool) -> typing.Optional[str]: if not b: return None b_pair, b_inbound, b_outbound = ReplyTop.get_user_top_strast(find_in_cid, b.uid) mutual_sign = ' ❤' if type == 'pair' and b_pair: mutual = mutual_sign if b_pair.uid == user_id else '' return f'Парная: {ReplyLove.get_fullname_or_username(b)}{mutual}' if type == 'inbound' and b_inbound: mutual = mutual_sign if b_inbound and b_inbound.uid == user_id else '' return f'Входящая: {ReplyLove.get_fullname_or_username(b)}{mutual}' if type == 'outbound' and b_outbound: mutual = mutual_sign if b_outbound and b_outbound.uid == user_id else '' return f'Исходящая: {ReplyLove.get_fullname_or_username(b)}{mutual}' return None bot.sendChatAction(send_to_cid, ChatAction.TYPING) reply_to_msg = update.message.reply_to_message if reply_to_msg: user_id = reply_to_msg.from_user.id else: splitted = update.message.text.split() if len(splitted) == 2: user_id = User.get_id_by_name(splitted[1]) else: user_id = update.message.from_user.id user = User.get(user_id) if not user: bot.send_message(send_to_cid, 'А кто это? Таких не знаю.', reply_to_message_id=update.message.message_id) return pair, inbound, outbound = ReplyTop.get_user_top_strast(find_in_cid, user_id) formats = (format_love('pair', pair, user.female), format_love('inbound', inbound, user.female), format_love('outbound', outbound, user.female)) love_list = [s for s in formats if s] if len(love_list) == 0: result = '🤷♀️🤷♂️ А нет никакой страсти' else: result = '\n'.join(love_list) if user_id in CONFIG.get('replylove__dragon_lovers', []): result = '🐉' bot.send_message(send_to_cid, f'Страсть {user.get_username_or_link()}:\n\n{result}', reply_to_message_id=update.message.message_id, parse_mode=ParseMode.HTML)
def find_users(message: telegram.Message, usernames: List[str]) -> Tuple[List[str], Set[int], List[str]]: """ Ищет пользователей по таким юзернеймам. Возвращает кортеж: - список найденных uid - список найденных юзернеймов - список ненайденных юзернеймов """ not_found_usernames: List[str] = [] found_uids: Set[int] = set() found_usernames: List[str] = [] for username in usernames: uid = User.get_id_by_name(username) if uid is None: # на случай если вместо юзернейма указан цифровой user_id user = User.get(username) if user is not None: uid = user.uid if uid is None: not_found_usernames.append(username) continue found_uids.add(uid) found_usernames.append(username.lstrip('@')) # ищем упоминания людей без юзернейма for entity, _ in message.parse_entities().items(): if entity.type == 'text_mention': uid = entity.user.id if uid is None: continue user = User.get(uid) if user is None: continue found_uids.add(uid) found_usernames.append(user.fullname) return not_found_usernames, found_uids, found_usernames
def format_chat_users(chat_id: int, uids: Iterable[int]) -> List[str]: """ Возвращает юзернеймы (с тегами) тех uids, что есть в чате. """ users = [] chat_uids: Set[int] = {chat_user.uid for chat_user in ChatUser.get_all(chat_id)} for uid in uids: user = User.get(uid) if user is None: continue if uid not in chat_uids: continue users.append(user.get_username_or_link()) return users
def get_current_state(meta_data): """ Gets state of the user in conversation which gives info about where he is in conversation Gets info the flow/business to which user belongs to For e.g. current_node_id of flow exists in state """ sender_type = SenderType.get_name(meta_data["senderType"]) if sender_type == "AGENT": user_id = meta_data["recipient"]["id"] business_id = meta_data["sender"]["id"] else: user_id = meta_data["sender"]["id"] business_id = meta_data["recipient"]["id"] state = User(user_id).get_session_data(meta_data=meta_data) flow_id = meta_data.get("flowId") # business_id = flow_id if flow_id else business_id business_data = Business(business_id).get_info() logger.debug(f"Business data is {business_data}") # if state has flow_id use it else use flowId from meta_data # else use flow_id got from business_id for backwards compatibility if state.get("flow_id"): state["flow_id"] = state.get("flow_id") elif flow_id: state["flow_id"] = flow_id else: state["flow_id"] = business_data.get("flow_id", "") # state["flow_id"] = state.get("flow_id") if state.get("flow_id") else flow_data.get("flow_id", "") state["business_name"] = business_data.get("business_name", "") state["business_id"] = business_data.get("business_id") # current_state = Util.merge_dicts(state, flow_data) return state
def __get_top_informer(cls) -> str: users = cache.get(cls.key_users_stats) if not users: return '' users_sorted_by_donos: typing.List[typing.Tuple[int, dict]] = sorted( users.items(), key=lambda user: user[1]['case_types'][int(FSBDayTextType.donos)], reverse=True) if len(users_sorted_by_donos) == 0: return '' uid, stats = users_sorted_by_donos[0] user = User.get(uid) female = 'а' if user.female else '' return f'Больше всего доносов написал{female} {user.get_username_or_link()}'
def __update_notifications(cls, card_id: int, type: str, uids: List[int]): key = f"{CACHE_PREFIX}:viewed:{card_id}:{type}" viewed = cache.get(key, []) updated = [] result = [] for uid in uids: updated.append(uid) user = User.get(uid) username = user.get_username_or_link() if User else str(uid) result.append({ "user": username, "viewed": uid in viewed, }) cache.set(key, updated, time=USER_CACHE_EXPIRE) return result
def load_user(user_id): return User.get(user_id)