Skip to content

Commit

Permalink
kicked users (#24)
Browse files Browse the repository at this point in the history
* kicked users

Co-authored-by: Roman <roman.rey@hawk.ai>
  • Loading branch information
rooom13 and hawk-roman-rey authored Apr 2, 2022
1 parent 46f8e78 commit c4ac2ee
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 24 deletions.
19 changes: 10 additions & 9 deletions daily_word_bot/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging
from datetime import datetime

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, BotCommand
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, BotCommand, ParseMode
from telegram.error import Unauthorized
from telegram.ext import (Updater,
CommandHandler, CallbackQueryHandler, ConversationHandler, MessageHandler,
Expand Down Expand Up @@ -49,7 +49,7 @@ def wrapper(*args, **kwargs):
if self.is_admin(update.effective_message.chat.id):
return func(*args, **kwargs)
else:
update.effective_message.reply_text(self.admin_msg, parse_mode='HTML')
update.effective_message.reply_text(self.admin_msg, parse_mode=ParseMode.HTML)
return wrapper


Expand All @@ -65,9 +65,10 @@ def wrapper(self, user, *kargs, **kwargs):
except Unauthorized as e:
is_blocked = "blocked" in e.message
is_deactivated = "deactivated" in e.message
if not (is_blocked or is_deactivated):
is_kicked = "kicked" in e.message
if not (is_blocked or is_deactivated or is_kicked):
raise e
self.dao.set_user_inactive(chat_id, is_blocked, is_deactivated)
self.dao.set_user_inactive(chat_id, is_blocked, is_deactivated, is_kicked)

# Any other errors must be reported
except Exception as e:
Expand Down Expand Up @@ -184,7 +185,7 @@ def callback_on_addlevel(self, update: Update, context: CallbackContext) -> None
def callback_on_info(self, update: Update, context: CallbackContext) -> None: # pragma: no cover
msg = f"""Version: <i>{config.VERSION}</i> deployed on {self.start_date}
\nWord bank info:\n - {len(self.word_bank.df.index)} words, last updated on {self.word_bank.last_updated_at}"""
update.message.reply_text(msg, parse_mode='HTML')
update.message.reply_text(msg, parse_mode=ParseMode.HTML)

def callback_on_get_blockwords_callback(self, update: Update, context: CallbackContext) -> None: # pragma: no cover

Expand Down Expand Up @@ -256,7 +257,7 @@ def callback_on_cancel(self, update: Update, context: CallbackContext) -> None:
def callback_on_users(self, update: Update, context: CallbackContext) -> None: # pragma: no cover
users = list(self.dao.get_all_users())
msg = utils.build_users_msg(users)
update.message.reply_text(msg)
update.message.reply_text(msg, parse_mode=ParseMode.HTML)

@admin_only
def callback_on_broadcast(self, update: Update, context: CallbackContext) -> None: # pragma: no cover
Expand All @@ -267,7 +268,7 @@ def callback_on_broadcast(self, update: Update, context: CallbackContext) -> Non
@admin_only
def callback_on_broadcast_confirm(self, update: Update, context: CallbackContext) -> None: # pragma: no cover
msg = utils.build_broadcast_preview_msg(update.message.text)
update.effective_message.reply_text(msg, parse_mode='HTML', reply_markup=InlineKeyboardMarkup(
update.effective_message.reply_text(msg, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("Send", callback_data="/broadcast_send"), (Buttons.cancel[0][0])]]
))
return States.BROADCAST_CONFIRM
Expand Down Expand Up @@ -299,7 +300,7 @@ def job_callback_send_word(self, context: CallbackContext): # pragma: no cover
@handle_error_send_user
def send_message_to_user(self, user: dict, msg: str, reply_markup=None):
chat_id = user["chatId"]
self.updater.bot.send_message(chat_id=chat_id, text=msg, reply_markup=reply_markup, parse_mode='HTML')
self.updater.bot.send_message(chat_id=chat_id, text=msg, reply_markup=reply_markup, parse_mode=ParseMode.HTML)

@handle_error_send_user
def send_user_word(self, user: dict): # pragma: no cover
Expand All @@ -325,7 +326,7 @@ def callback_chrono_backup(self, context: CallbackContext): # pragma: no cover

def send_message_to_admins(self, msg: str): # pragma: no cover
for chat_id in config.ADMIN_CHAT_IDS:
self.updater.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')
self.updater.bot.send_message(chat_id=chat_id, text=msg, parse_mode=ParseMode.HTML)

@staticmethod
def is_admin(chat_id: str):
Expand Down
9 changes: 8 additions & 1 deletion daily_word_bot/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,24 @@ def save_user(self, message: Message, levels: list):
isActive=True,
isBlocked=False,
isDeactivated=False,
isKicked=False,
levels=levels
))
self.r.set(f"userInfo:{chat_id}", user_info)

def set_user_inactive(self, chat_id: str, is_blocked: bool = False, is_deactivated: bool = False):
def set_user_inactive(self, chat_id: str,
is_blocked: bool = False,
is_deactivated: bool = False,
is_kicked: bool = False
):
user_info: dict = self.get_user(chat_id)
user_info["isActive"] = False
if is_blocked:
user_info["isBlocked"] = True
if is_deactivated:
user_info["isDeactivated"] = True
if is_kicked:
user_info["isKicked"] = True

self.r.set(f"userInfo:{chat_id}", json.dumps(user_info))

Expand Down
41 changes: 33 additions & 8 deletions daily_word_bot/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
import os
from collections import defaultdict
from typing import List
from telegram import BotCommand, InlineKeyboardButton, InlineKeyboardMarkup

Expand All @@ -12,6 +13,18 @@ def highlight(w: str) -> str:
return f"<b>{w}</b>"


def user_to_string(user: dict) -> str:
chat_id = user.get("chatId")
name = user.get("name")
is_active = "😀" if user.get("isActive") else "😴"
is_blocked = "⛔" if user.get("isBlocked") else ""
is_deactivated = "📵" if user.get("isDeactivated") else ""
is_kicked = "🥾" if user.get("isKicked") else ""
levels = "".join(f"{level[0]}" for level in user.get("levels") or [])

return (f"- {chat_id} {name} {is_active}{is_blocked}{is_deactivated}{is_kicked}" + (f" <i>{levels}</i>" if levels else ""))


def build_levels_answer(user_levels: list) -> dict:
# build the message and send it back to the user
msg = "🛠 Choose the level of the words to be sent.\nClick the empty checkbox ⬜️ to assign or the filled one ✅ to unassign a level. 🛠\n\nThese are your word levels: "
Expand Down Expand Up @@ -85,18 +98,30 @@ def build_available_commands_msg(bot_commands: List[BotCommand]) -> str:


def build_users_msg(users: List[dict]) -> str:
msg = f"Users: ({len(users)})"

users_classified = defaultdict(list)

# tuple with user classification key & bool function that classifies
# note that order matters, that's why 'active' is the last one with a constant True
classifications = [
("deactivated", lambda u: u.get("isDeactivated")),
("blocked", lambda u: u.get("isBlocked")),
("kicked", lambda u: u.get("isKicked")),
("stopped", lambda u: not u.get("isActive")),
("active", lambda u: True)
]

for u in users:
for key, classification_fun in classifications:
if classification_fun(u):
users_classified[key].append(u)
break

chat_id = u.get("chatId")
name = u.get("name")
is_active = "😀" if u.get("isActive") else "😴"
is_blocked = "⛔" if u.get("isBlocked") else ""
is_deactivated = "📵" if u.get("isDeactivated") else ""
msg = f"Total users: ({len(users)})"

levels = "".join(f"{level[0]}" for level in u.get("levels") or [])
msg += f"\n- {chat_id} {name} {is_active}{is_blocked}{is_deactivated} {levels}"
for key, _ in classifications:
users_c = users_classified[key]
msg += f"\n\n<b>{key}</b> ({len(users_c)})\n" + "\n".join([utils.user_to_string(user) for user in users_c])

return msg

Expand Down
2 changes: 2 additions & 0 deletions tests/test_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
isActive=True,
isDeactivated=False,
isBlocked=False,
isKicked=False,
levels=[]
)
dao = DAO(config.REDIS_HOST)
Expand Down Expand Up @@ -45,6 +46,7 @@ def test_get_all_users():
@pytest.mark.parametrize("kwargs", [
{"is_blocked": True},
{"is_deactivated": True},
{"is_kicked": True},
])
def test_set_user_inactive(kwargs):
dao.save_user(message, levels=[])
Expand Down
36 changes: 30 additions & 6 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,37 @@ def test_build_available_commands_msg():


def test_build_users_msg():
users = [{'name': 'romanito', 'isActive': True, 'chatId': 'aChatId'},
{'name': 'pinxulino', 'isActive': False, 'chatId': 'aChatId2', 'levels': ['beginner', "intermediate"]}]
users = [
{'name': 'romanito', 'isActive': True, 'chatId': 'aChatId', 'levels': ['beginner', 'intermediate']},
{'name': 'romanito', 'isActive': True, 'chatId': 'aChatId'},
{'name': 'ramonito', 'isActive': False, 'chatId': 'aChatId', 'isDeactivated': True, },
{'name': 'ramonito', 'isActive': False, 'chatId': 'aChatId', 'isKicked': True, },
{'name': 'pepeblock', 'isActive': False, 'chatId': 'aChatId', 'isBlocked': True, },
{'name': 'popiblock', 'isActive': False, 'chatId': 'aChatId', 'isBlocked': True, },
{'name': 'pinxulino', 'isActive': False, 'chatId': 'aChatId2'},

]
res = utils.build_users_msg(users)
tc.assertEqual(res,
"Users: (2)"
"\n- aChatId romanito 😀 "
"\n- aChatId2 pinxulino 😴 bi")
assert res == (
"Total users: (7)"
"\n"
"\n<b>deactivated</b> (1)"
"\n- aChatId ramonito 😴📵"
"\n"
"\n<b>blocked</b> (2)"
"\n- aChatId pepeblock 😴⛔"
"\n- aChatId popiblock 😴⛔"
"\n"
"\n<b>kicked</b> (1)"
"\n- aChatId ramonito 😴🥾"
"\n"
"\n<b>stopped</b> (1)"
"\n- aChatId2 pinxulino 😴"
"\n"
"\n<b>active</b> (2)"
"\n- aChatId romanito 😀 <i>bi</i>"
"\n- aChatId romanito 😀"
)


@pytest.mark.parametrize("levels,expected_inline_keyboard_buttons", [
Expand Down

0 comments on commit c4ac2ee

Please sign in to comment.