From 1c713de46d9c785fd74a50e62f3366bff880de2f Mon Sep 17 00:00:00 2001 From: Jerry Date: Thu, 7 Dec 2017 16:27:51 +0800 Subject: [PATCH] Add /kick command and remove botan support (#38) * kick handler test * Add authentication and fix bugs * Add help text * minor fix * Remove useless comments * Get user object from reply first. * Update bot.py * minor fix * update help text * Update AUTHORS.md * Remove old /kick implementation * minor fix * Manually merge upstream changes * No need to accept args * remove unused chat_setting.py * botan * import botan from submodule for compatibility with python-telegram-bot 8.1+ * fix typo * Update requirements.txt * delete submodule * Drop botan support completely * Refine the way of getting config * Bug fix --- AUTHORS.md | 3 +- README.md | 3 +- actions.py | 10 +---- bot.py | 77 ++++++++++++++++++++++++++++++++++-- config.json.example | 8 +++- chat_setting.py => config.py | 16 +++++++- game.py | 11 ++---- gameplay_config.py | 6 --- player.py | 2 +- requirements.txt | 2 +- shared_vars.py | 12 +----- simple_commands.py | 2 + utils.py | 2 +- 13 files changed, 111 insertions(+), 43 deletions(-) rename chat_setting.py => config.py (58%) delete mode 100644 gameplay_config.py diff --git a/AUTHORS.md b/AUTHORS.md index 419ee08..3ebe34c 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -8,5 +8,6 @@ The following wonderful people contributed directly or indirectly to this projec - [imlonghao](https://github.com/imlonghao) - [qubitnerd](https://github.com/qubitnerd) +- [SYHGroup](https://github.com/SYHGroup) -Please add yourself here alphabetically when you submit your first pull request. \ No newline at end of file +Please add yourself here alphabetically when you submit your first pull request. diff --git a/README.md b/README.md index db45387..0e40070 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ To run the bot yourself, you will need: - Use `/setinline` and `/setinlinefeedback` with BotFather for your bot. - Install requirements (using a `virtualenv` is recommended): `pip install -r requirements.txt` -You can change some gameplay parameters like turn times, minimum amount of players and default gamemode in `gameplay_config.py`. Check the gamemodes available with the `/modes` command. +You can change some gameplay parameters like turn times, minimum amount of players and default gamemode in `config.json`. +Current gamemodes available: classic, fast and wild. Check the details with the `/modes` command. Then run the bot with `python3 bot.py`. diff --git a/actions.py b/actions.py index 958e755..c8c5f1e 100644 --- a/actions.py +++ b/actions.py @@ -7,10 +7,10 @@ from datetime import datetime from telegram import Message, Chat -from gameplay_config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME +from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME from errors import DeckEmptyError, NotEnoughPlayersError from internationalization import __, _ -from shared_vars import gm, botan +from shared_vars import gm from user_setting import UserSetting from utils import send_async, display_name, game_is_running @@ -128,12 +128,6 @@ def do_play_card(bot, player, result_id): gm.end_game(chat, user) - if botan: - random_int = random.randrange(1, 999999999) - botan.track(Message(random_int, user, datetime.now(), - Chat(chat.id, 'group')), - 'Played cards') - def do_draw(bot, player): """Does the drawing""" diff --git a/bot.py b/bot.py index ed3f21c..cdd2ae4 100644 --- a/bot.py +++ b/bot.py @@ -30,14 +30,14 @@ import card as c import settings import simple_commands from actions import do_skip, do_play_card, do_draw, do_call_bluff, start_player_countdown -from gameplay_config import WAITING_TIME, DEFAULT_GAMEMODE, MIN_PLAYERS +from config import WAITING_TIME, DEFAULT_GAMEMODE, MIN_PLAYERS from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError, NotEnoughPlayersError, DeckEmptyError) from internationalization import _, __, user_locale, game_locales from results import (add_call_bluff, add_choose_color, add_draw, add_gameinfo, add_no_game, add_not_started, add_other_cards, add_pass, add_card, add_mode_classic, add_mode_fast, add_mode_wild) -from shared_vars import botan, gm, updater, dispatcher +from shared_vars import gm, updater, dispatcher from simple_commands import help_handler from start_bot import start_bot from utils import display_name @@ -93,8 +93,6 @@ def new_game(bot, update): text=_("Created a new game! Join the game with /join " "and start the game with /start")) - if botan: - botan.track(update.message, 'New games') @user_locale def kill_game(bot, update): @@ -215,6 +213,76 @@ def leave_game(bot, update): reply_to_message_id=update.message.message_id) +@user_locale +def kick_player(bot, update): + """Handler for the /kick command""" + + if update.message.chat.type == 'private': + help_handler(bot, update) + return + + chat = update.message.chat + user = update.message.from_user + + try: + game = gm.chatid_games[chat.id][-1] + + except (KeyError, IndexError): + send_async(bot, chat.id, + text=_("No game is running at the moment. " + "Create a new game with /new"), + reply_to_message_id=update.message.message_id) + return + + if not game.started: + send_async(bot, chat.id, + text=_("The game is not started yet. " + "Join the game with /join and start the game with /start"), + reply_to_message_id=update.message.message_id) + return + + if user_is_creator_or_admin(user, game, bot, chat): + + if update.message.reply_to_message: + kicked = update.message.reply_to_message.from_user + + try: + gm.leave_game(kicked, chat) + + except NoGameInChatError: + send_async(bot, chat.id, text=_("Player {name} is not found in the current game.".format(name=display_name(kicked))), + reply_to_message_id=update.message.message_id) + return + + except NotEnoughPlayersError: + gm.end_game(chat, user) + send_async(bot, chat.id, + text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) + send_async(bot, chat.id, text=__("Game ended!", multi=game.translate)) + return + + send_async(bot, chat.id, + text=_("{0} was kicked by {1}".format(display_name(kicked), display_name(user)))) + + else: + send_async(bot, chat.id, + text=_("Please reply to the person you want to kick and type /kick again."), + reply_to_message_id=update.message.message_id) + return + + send_async(bot, chat.id, + text=__("Okay. Next Player: {name}", + multi=game.translate).format( + name=display_name(game.current_player.user)), + reply_to_message_id=update.message.message_id) + + else: + send_async(bot, chat.id, + text=_("Only the game creator ({name}) and admin can do that.") + .format(name=game.starter.first_name), + reply_to_message_id=update.message.message_id) + + def select_game(bot, update): """Handler for callback queries to select the current game""" @@ -652,6 +720,7 @@ dispatcher.add_handler(CommandHandler('new', new_game)) dispatcher.add_handler(CommandHandler('kill', kill_game)) dispatcher.add_handler(CommandHandler('join', join_game)) dispatcher.add_handler(CommandHandler('leave', leave_game)) +dispatcher.add_handler(CommandHandler('kick', kick_player)) dispatcher.add_handler(CommandHandler('open', open_game)) dispatcher.add_handler(CommandHandler('close', close_game)) dispatcher.add_handler(CommandHandler('enable_translations', diff --git a/config.json.example b/config.json.example index 0a851a0..1c89c9e 100644 --- a/config.json.example +++ b/config.json.example @@ -1,8 +1,12 @@ { "token": "token_here", - "botan_token": null, "admin_list": [0], "open_lobby": true, "enable_translations": false, - "workers": 32 + "workers": 32, + "default_gamemode": "fast", + "waiting_time": 120, + "time_removal_after_skip": 20, + "min_fast_turn_time": 15, + "min_players": 2 } diff --git a/chat_setting.py b/config.py similarity index 58% rename from chat_setting.py rename to config.py index c9cfc0c..6e20066 100644 --- a/chat_setting.py +++ b/config.py @@ -18,4 +18,18 @@ # along with this program. If not, see . -pass +import json + +with open("config.json","r") as f: + config = json.loads(f.read()) + +TOKEN=config.get("token") +WORKERS=config.get("workers", 32) +ADMIN_LIST = config.get("admin_list", None) +OPEN_LOBBY = config.get("open_lobby", True) +ENABLE_TRANSLATIONS = config.get("enable_translations", False) +DEFAULT_GAMEMODE = config.get("default_gamemode", "fast") +WAITING_TIME = config.get("waiting_time", 120) +TIME_REMOVAL_AFTER_SKIP = config.get("time_removal_after_skip", 20) +MIN_FAST_TURN_TIME = config.get("min_fast_turn_time", 15) +MIN_PLAYERS = config.get("min_players", 2) diff --git a/game.py b/game.py index 1d59d98..3234f9b 100644 --- a/game.py +++ b/game.py @@ -19,10 +19,9 @@ import logging -import json +from config import ADMIN_LIST, OPEN_LOBBY, DEFAULT_GAMEMODE, ENABLE_TRANSLATIONS from datetime import datetime -from gameplay_config import DEFAULT_GAMEMODE from deck import Deck import card as c @@ -37,11 +36,9 @@ class Game(object): starter = None mode = DEFAULT_GAMEMODE job = None - with open("config.json","r") as f: - config = json.loads(f.read()) - owner = config.get("admin_list", None) - open = config.get("open_lobby", True) - translate = config.get("enable_translations", False) + owner = ADMIN_LIST + open = OPEN_LOBBY + translate = ENABLE_TRANSLATIONS def __init__(self, chat): self.chat = chat diff --git a/gameplay_config.py b/gameplay_config.py deleted file mode 100644 index 1d2b82e..0000000 --- a/gameplay_config.py +++ /dev/null @@ -1,6 +0,0 @@ -# Current gamemodes: "classic", "fast", "wild" -DEFAULT_GAMEMODE = "fast" -WAITING_TIME = 120 -TIME_REMOVAL_AFTER_SKIP = 20 -MIN_FAST_TURN_TIME = 15 -MIN_PLAYERS = 2 \ No newline at end of file diff --git a/player.py b/player.py index df3ce1e..e207239 100644 --- a/player.py +++ b/player.py @@ -23,7 +23,7 @@ from datetime import datetime import card as c from errors import DeckEmptyError -from gameplay_config import WAITING_TIME +from config import WAITING_TIME class Player(object): diff --git a/requirements.txt b/requirements.txt index b870614..e2d30a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -python-telegram-bot==7.0.1 +python-telegram-bot==8.1.1 pony diff --git a/shared_vars.py b/shared_vars.py index 52f412b..ad47c50 100644 --- a/shared_vars.py +++ b/shared_vars.py @@ -17,11 +17,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import json +from config import TOKEN, WORKERS import logging from telegram.ext import Updater -from telegram.contrib.botan import Botan from game_manager import GameManager from database import db @@ -30,12 +29,5 @@ db.bind('sqlite', 'uno.sqlite3', create_db=True) db.generate_mapping(create_tables=True) gm = GameManager() -with open("config.json","r") as f: - config = json.loads(f.read()) -updater = Updater(token=config.get("token"), workers=config.get("workers", 32)) +updater = Updater(token=TOKEN, workers=WORKERS) dispatcher = updater.dispatcher - -if config.get("botan_token"): - botan = Botan(config.get("botan_token")) -else: - botan = None \ No newline at end of file diff --git a/simple_commands.py b/simple_commands.py index 368513e..6cc0c23 100644 --- a/simple_commands.py +++ b/simple_commands.py @@ -47,6 +47,8 @@ help_text = ("Follow these steps:\n\n" "/close - Close lobby\n" "/open - Open lobby\n" "/kill - Terminate the game\n" + "/kick - Select a player to kick " + "by replying to him or her\n" "/enable_translations - Translate relevant texts into all " "languages spoken in a game\n" "/disable_translations - Use English for those texts\n\n" diff --git a/utils.py b/utils.py index 37c584a..23b90b6 100644 --- a/utils.py +++ b/utils.py @@ -125,4 +125,4 @@ def user_is_creator_or_admin(user, game, bot, chat): @MWT(timeout=60*60) def get_admin_ids(bot, chat_id): """Returns a list of admin IDs for a given chat. Results are cached for 1 hour.""" - return [admin.user.id for admin in bot.get_chat_administrators(chat_id)] \ No newline at end of file + return [admin.user.id for admin in bot.get_chat_administrators(chat_id)]