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
This commit is contained in:
parent
187cc6f4ea
commit
1c713de46d
13 changed files with 111 additions and 43 deletions
|
@ -8,5 +8,6 @@ The following wonderful people contributed directly or indirectly to this projec
|
||||||
|
|
||||||
- [imlonghao](https://github.com/imlonghao)
|
- [imlonghao](https://github.com/imlonghao)
|
||||||
- [qubitnerd](https://github.com/qubitnerd)
|
- [qubitnerd](https://github.com/qubitnerd)
|
||||||
|
- [SYHGroup](https://github.com/SYHGroup)
|
||||||
|
|
||||||
Please add yourself here alphabetically when you submit your first pull request.
|
Please add yourself here alphabetically when you submit your first pull request.
|
||||||
|
|
|
@ -16,7 +16,8 @@ To run the bot yourself, you will need:
|
||||||
- Use `/setinline` and `/setinlinefeedback` with BotFather for your bot.
|
- Use `/setinline` and `/setinlinefeedback` with BotFather for your bot.
|
||||||
- Install requirements (using a `virtualenv` is recommended): `pip install -r requirements.txt`
|
- 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`.
|
Then run the bot with `python3 bot.py`.
|
||||||
|
|
||||||
|
|
10
actions.py
10
actions.py
|
@ -7,10 +7,10 @@ from datetime import datetime
|
||||||
|
|
||||||
from telegram import Message, Chat
|
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 errors import DeckEmptyError, NotEnoughPlayersError
|
||||||
from internationalization import __, _
|
from internationalization import __, _
|
||||||
from shared_vars import gm, botan
|
from shared_vars import gm
|
||||||
from user_setting import UserSetting
|
from user_setting import UserSetting
|
||||||
from utils import send_async, display_name, game_is_running
|
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)
|
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):
|
def do_draw(bot, player):
|
||||||
"""Does the drawing"""
|
"""Does the drawing"""
|
||||||
|
|
77
bot.py
77
bot.py
|
@ -30,14 +30,14 @@ import card as c
|
||||||
import settings
|
import settings
|
||||||
import simple_commands
|
import simple_commands
|
||||||
from actions import do_skip, do_play_card, do_draw, do_call_bluff, start_player_countdown
|
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,
|
from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError,
|
||||||
NotEnoughPlayersError, DeckEmptyError)
|
NotEnoughPlayersError, DeckEmptyError)
|
||||||
from internationalization import _, __, user_locale, game_locales
|
from internationalization import _, __, user_locale, game_locales
|
||||||
from results import (add_call_bluff, add_choose_color, add_draw, add_gameinfo,
|
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_no_game, add_not_started, add_other_cards, add_pass,
|
||||||
add_card, add_mode_classic, add_mode_fast, add_mode_wild)
|
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 simple_commands import help_handler
|
||||||
from start_bot import start_bot
|
from start_bot import start_bot
|
||||||
from utils import display_name
|
from utils import display_name
|
||||||
|
@ -93,8 +93,6 @@ def new_game(bot, update):
|
||||||
text=_("Created a new game! Join the game with /join "
|
text=_("Created a new game! Join the game with /join "
|
||||||
"and start the game with /start"))
|
"and start the game with /start"))
|
||||||
|
|
||||||
if botan:
|
|
||||||
botan.track(update.message, 'New games')
|
|
||||||
|
|
||||||
@user_locale
|
@user_locale
|
||||||
def kill_game(bot, update):
|
def kill_game(bot, update):
|
||||||
|
@ -215,6 +213,76 @@ def leave_game(bot, update):
|
||||||
reply_to_message_id=update.message.message_id)
|
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):
|
def select_game(bot, update):
|
||||||
"""Handler for callback queries to select the current game"""
|
"""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('kill', kill_game))
|
||||||
dispatcher.add_handler(CommandHandler('join', join_game))
|
dispatcher.add_handler(CommandHandler('join', join_game))
|
||||||
dispatcher.add_handler(CommandHandler('leave', leave_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('open', open_game))
|
||||||
dispatcher.add_handler(CommandHandler('close', close_game))
|
dispatcher.add_handler(CommandHandler('close', close_game))
|
||||||
dispatcher.add_handler(CommandHandler('enable_translations',
|
dispatcher.add_handler(CommandHandler('enable_translations',
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
{
|
{
|
||||||
"token": "token_here",
|
"token": "token_here",
|
||||||
"botan_token": null,
|
|
||||||
"admin_list": [0],
|
"admin_list": [0],
|
||||||
"open_lobby": true,
|
"open_lobby": true,
|
||||||
"enable_translations": false,
|
"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
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,4 +18,18 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
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)
|
11
game.py
11
game.py
|
@ -19,10 +19,9 @@
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import json
|
from config import ADMIN_LIST, OPEN_LOBBY, DEFAULT_GAMEMODE, ENABLE_TRANSLATIONS
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from gameplay_config import DEFAULT_GAMEMODE
|
|
||||||
from deck import Deck
|
from deck import Deck
|
||||||
import card as c
|
import card as c
|
||||||
|
|
||||||
|
@ -37,11 +36,9 @@ class Game(object):
|
||||||
starter = None
|
starter = None
|
||||||
mode = DEFAULT_GAMEMODE
|
mode = DEFAULT_GAMEMODE
|
||||||
job = None
|
job = None
|
||||||
with open("config.json","r") as f:
|
owner = ADMIN_LIST
|
||||||
config = json.loads(f.read())
|
open = OPEN_LOBBY
|
||||||
owner = config.get("admin_list", None)
|
translate = ENABLE_TRANSLATIONS
|
||||||
open = config.get("open_lobby", True)
|
|
||||||
translate = config.get("enable_translations", False)
|
|
||||||
|
|
||||||
def __init__(self, chat):
|
def __init__(self, chat):
|
||||||
self.chat = chat
|
self.chat = chat
|
||||||
|
|
|
@ -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
|
|
|
@ -23,7 +23,7 @@ from datetime import datetime
|
||||||
|
|
||||||
import card as c
|
import card as c
|
||||||
from errors import DeckEmptyError
|
from errors import DeckEmptyError
|
||||||
from gameplay_config import WAITING_TIME
|
from config import WAITING_TIME
|
||||||
|
|
||||||
|
|
||||||
class Player(object):
|
class Player(object):
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
python-telegram-bot==7.0.1
|
python-telegram-bot==8.1.1
|
||||||
pony
|
pony
|
||||||
|
|
|
@ -17,11 +17,10 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
from config import TOKEN, WORKERS
|
||||||
import logging
|
import logging
|
||||||
from telegram.ext import Updater
|
from telegram.ext import Updater
|
||||||
from telegram.contrib.botan import Botan
|
|
||||||
|
|
||||||
from game_manager import GameManager
|
from game_manager import GameManager
|
||||||
from database import db
|
from database import db
|
||||||
|
@ -30,12 +29,5 @@ db.bind('sqlite', 'uno.sqlite3', create_db=True)
|
||||||
db.generate_mapping(create_tables=True)
|
db.generate_mapping(create_tables=True)
|
||||||
|
|
||||||
gm = GameManager()
|
gm = GameManager()
|
||||||
with open("config.json","r") as f:
|
updater = Updater(token=TOKEN, workers=WORKERS)
|
||||||
config = json.loads(f.read())
|
|
||||||
updater = Updater(token=config.get("token"), workers=config.get("workers", 32))
|
|
||||||
dispatcher = updater.dispatcher
|
dispatcher = updater.dispatcher
|
||||||
|
|
||||||
if config.get("botan_token"):
|
|
||||||
botan = Botan(config.get("botan_token"))
|
|
||||||
else:
|
|
||||||
botan = None
|
|
|
@ -47,6 +47,8 @@ help_text = ("Follow these steps:\n\n"
|
||||||
"/close - Close lobby\n"
|
"/close - Close lobby\n"
|
||||||
"/open - Open lobby\n"
|
"/open - Open lobby\n"
|
||||||
"/kill - Terminate the game\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 "
|
"/enable_translations - Translate relevant texts into all "
|
||||||
"languages spoken in a game\n"
|
"languages spoken in a game\n"
|
||||||
"/disable_translations - Use English for those texts\n\n"
|
"/disable_translations - Use English for those texts\n\n"
|
||||||
|
|
2
utils.py
2
utils.py
|
@ -125,4 +125,4 @@ def user_is_creator_or_admin(user, game, bot, chat):
|
||||||
@MWT(timeout=60*60)
|
@MWT(timeout=60*60)
|
||||||
def get_admin_ids(bot, chat_id):
|
def get_admin_ids(bot, chat_id):
|
||||||
"""Returns a list of admin IDs for a given chat. Results are cached for 1 hour."""
|
"""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)]
|
return [admin.user.id for admin in bot.get_chat_administrators(chat_id)]
|
||||||
|
|
Loading…
Reference in a new issue