diff --git a/blackjack/game/blackjackgame.py b/blackjack/game/blackjackgame.py
index 55bd28f..2e450f4 100644
--- a/blackjack/game/blackjackgame.py
+++ b/blackjack/game/blackjackgame.py
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
import logging
-
+from datetime import datetime
from enum import Enum
+
import blackjack.errors as errors
from blackjack.game import Player, Dealer, Deck
@@ -17,6 +18,7 @@ def __init__(self, gametype=None, game_id=None, lang_id="en"):
self.list_won = []
self.list_tie = []
self.list_lost = []
+ self.datetime_started = datetime.now()
self.bets_active = True
self._current_player = 0
self.players = []
diff --git a/blackjackbot/__init__.py b/blackjackbot/__init__.py
index be61da0..f82e84d 100644
--- a/blackjackbot/__init__.py
+++ b/blackjackbot/__init__.py
@@ -14,6 +14,7 @@
stop_command_handler = CommandHandler("stop", game.stop_cmd)
language_command_handler = CommandHandler("language", settings.language_cmd)
stats_command_handler = CommandHandler("stats", util.stats_cmd)
+resetstats_command_handler = CommandHandler("resetstats", util.reset_stats_cmd)
comment_command_handler = CommandHandler("comment", util.comment_cmd)
comment_text_command_handler = MessageHandler(Filters.text & ~(Filters.forwarded | Filters.command), util.comment_text)
@@ -33,12 +34,13 @@
start_callback_handler = CallbackQueryHandler(game.start_callback, pattern=r"^start_[0-9]{7}$")
newgame_callback_handler = CallbackQueryHandler(game.newgame_callback, pattern=r"^newgame$")
language_callback_handler = CallbackQueryHandler(settings.language_callback, pattern=r"^lang_([a-z]{2}(?:-[a-z]{2})?)$")
+reset_stats_callback_handler = CallbackQueryHandler(util.reset_stats_callback, pattern=r"^reset_stats_(confirm|cancel)$")
handlers = [banned_user_handler,
start_command_handler, stop_command_handler, join_callback_handler, hit_callback_handler,
stand_callback_handler, start_callback_handler, language_command_handler, stats_command_handler,
newgame_callback_handler, reload_lang_command_handler, language_callback_handler, users_command_handler,
comment_command_handler, comment_text_command_handler, answer_command_handler, ban_command_handler,
- unban_command_handler, bans_command_handler]
+ unban_command_handler, bans_command_handler, resetstats_command_handler, reset_stats_callback_handler]
__all__ = ['handlers', 'error_handler']
diff --git a/blackjackbot/commands/game/commands.py b/blackjackbot/commands/game/commands.py
index a67a8ad..8f33459 100644
--- a/blackjackbot/commands/game/commands.py
+++ b/blackjackbot/commands/game/commands.py
@@ -168,12 +168,11 @@ def hit_callback(update, context):
player_cards = get_cards_string(player, lang_id)
if player.has_blackjack():
text = (translator("your_cards_are") + "\n\n" + translator("got_blackjack")).format(user_mention, player.cardvalue, player_cards)
- update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
- next_player(update, context)
- elif player.cardvalue == 21:
+ else:
text = (translator("your_cards_are") + "\n\n" + translator("got_21")).format(user_mention, player.cardvalue, player_cards)
- update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
- next_player(update, context)
+
+ update.effective_message.edit_text(text=text, parse_mode=ParseMode.HTML, reply_markup=None)
+ next_player(update, context)
@needs_active_game
diff --git a/blackjackbot/commands/util/__init__.py b/blackjackbot/commands/util/__init__.py
index d5afa54..f90b956 100644
--- a/blackjackbot/commands/util/__init__.py
+++ b/blackjackbot/commands/util/__init__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from .functions import remove_inline_keyboard, get_start_keyboard, generate_evaluation_string, html_mention, get_game_keyboard, get_join_keyboard
from .decorators import admin_method, needs_active_game
-from .commands import stats_cmd, comment_cmd, comment_text
+from .commands import stats_cmd, comment_cmd, comment_text, reset_stats_cmd, reset_stats_callback
__all__ = ['remove_inline_keyboard', 'get_start_keyboard', 'generate_evaluation_string', 'html_mention', 'get_game_keyboard', 'get_join_keyboard',
- 'stats_cmd', 'comment_cmd', 'comment_text', 'admin_method', 'needs_active_game']
+ 'stats_cmd', 'comment_cmd', 'comment_text', 'admin_method', 'needs_active_game', 'reset_stats_cmd', 'reset_stats_callback']
diff --git a/blackjackbot/commands/util/commands.py b/blackjackbot/commands/util/commands.py
index 8536c90..2eeff39 100644
--- a/blackjackbot/commands/util/commands.py
+++ b/blackjackbot/commands/util/commands.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-from telegram import ForceReply, ParseMode
+from telegram import ForceReply, ParseMode, InlineKeyboardButton, InlineKeyboardMarkup
from blackjackbot.commands.admin.functions import notify_admins
from blackjackbot.lang import translate
@@ -13,6 +13,58 @@ def stats_cmd(update, context):
update.message.reply_text(get_user_stats(update.effective_user.id), parse_mode=ParseMode.HTML)
+def reset_stats_cmd(update, context):
+ """Asks the user if they want to reset their statistics"""
+ user_id = update.effective_user.id
+ chat_id = update.effective_chat.id
+
+ _modify_old_reset_message(context)
+
+ db = Database()
+ lang_id = db.get_lang_id(user_id)
+
+ keyboard = [[
+ InlineKeyboardButton(translate("reset_stats_confirm_button"), callback_data='reset_stats_confirm'),
+ InlineKeyboardButton(translate("reset_stats_cancel_button"), callback_data='reset_stats_cancel'),
+ ]]
+ reply_markup = InlineKeyboardMarkup(keyboard)
+
+ sent_message = update.message.reply_text(translate("reset_stats_confirm", lang_id), reply_markup=reply_markup)
+ reset_message = {"message_id": sent_message.message_id, "chat_id": chat_id}
+ context.user_data["reset_messages"] = reset_message
+
+
+def _modify_old_reset_message(context):
+ """Removes the last saved reset confirmation messages from the chat history"""
+ reset_message = context.user_data.get("reset_message", None)
+ if reset_message is None:
+ return
+
+ try:
+ context.bot.edit_message_reply_markup(chat_id=reset_message.get("chat_id"), message_id=reset_message.get("message_id"))
+ except:
+ pass
+
+ context.user_data["reset_messages"] = None
+
+
+def reset_stats_callback(update, context):
+ """Handler for confirmation of statistics reset"""
+ query = update.callback_query
+ query.answer()
+
+ user_id = update.effective_user.id
+ db = Database()
+ lang_id = db.get_lang_id(user_id)
+
+ if query.data == "reset_stats_confirm":
+ db.reset_stats(user_id=user_id)
+ query.edit_message_text(translate("reset_stats_executed", lang_id))
+
+ elif query.data == "reset_stats_cancel":
+ query.edit_message_text(translate("reset_stats_cancelled", lang_id))
+
+
def comment_cmd(update, context):
"""MessageHandler callback for the /comment command"""
if context.user_data.get("state", UserState.IDLE) != UserState.IDLE:
diff --git a/blackjackbot/gamestore.py b/blackjackbot/gamestore.py
index ab59c8a..53960cb 100644
--- a/blackjackbot/gamestore.py
+++ b/blackjackbot/gamestore.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import logging
+from datetime import datetime, timedelta
from random import randint
from .errors.noactivegameexception import NoActiveGameException
@@ -82,3 +83,20 @@ def _game_stopped_callback(self, game):
self.remove_game(self._game_dict[game.id])
self.logger.debug("Current games: {}".format(len(self._chat_dict)))
+
+ def cleanup_stale_games(self):
+ stale_timeout_min = 10
+ now = datetime.now()
+ remove_chat_ids = []
+
+ for game_id, chat_id in self._game_dict.items():
+ game = self.get_game(chat_id)
+
+ game_older_than_10_mins = game.datetime_started < (now - timedelta(minutes=stale_timeout_min))
+ if game_older_than_10_mins:
+ logging.info("Killing game with id {} because it's stale for > {} mins".format(game.id, stale_timeout_min))
+ # TODO notify chat
+ remove_chat_ids.append(chat_id)
+
+ for chat_id in remove_chat_ids:
+ self.remove_game(chat_id)
diff --git a/blackjackbot/lang/strings/translations_en.json b/blackjackbot/lang/strings/translations_en.json
index 3b9e2de..a85db68 100644
--- a/blackjackbot/lang/strings/translations_en.json
+++ b/blackjackbot/lang/strings/translations_en.json
@@ -47,5 +47,11 @@
"admin_reply": "⚠ You need to reply to the user's comment!",
"reply_from_maintainer": "The maintainer of this bot sent you a reply:\n\n{}",
"statistic_template": "Here are your statistics 📊:\n\nPlayed Games: {}\nWon Games: {}\nLast Played: {} UTC\n\n{}\n\nWinning rate: {:.2%}",
- "dealer_name": "Dealer"
+ "dealer_name": "Dealer",
+ "reset_stats_confirm": "Do you really want to reset your statistics?",
+ "reset_stats_confirm_button": "Reset",
+ "reset_stats_cancel_button": "Cancel",
+ "reset_stats_executed": "Alright, I reset your statistics!",
+ "reset_stats_cancelled": "Okay, I did not reset your statistics!",
+ "no_stats": "You haven't played yet, there are no statistics for you."
}
diff --git a/bot.py b/bot.py
index bb8bc68..b170bf9 100644
--- a/bot.py
+++ b/bot.py
@@ -4,10 +4,11 @@
import logging.handlers
import pathlib
-from telegram.ext import Updater
+from telegram.ext import Updater, JobQueue
import config
from blackjackbot import handlers, error_handler
+from blackjackbot.gamestore import GameStore
logdir_path = pathlib.Path(__file__).parent.joinpath("logs").absolute()
logfile_path = logdir_path.joinpath("bot.log")
@@ -32,6 +33,16 @@
updater.dispatcher.add_error_handler(error_handler)
+
+# Set up jobs
+def stale_game_cleaner(context):
+ gs = GameStore()
+ gs.cleanup_stale_games()
+
+
+updater.job_queue.run_repeating(callback=stale_game_cleaner, interval=300, first=300)
+
+
if config.USE_WEBHOOK:
updater.start_webhook(listen=config.WEBHOOK_IP, port=config.WEBHOOK_PORT, url_path=config.BOT_TOKEN, cert=config.CERTPATH, webhook_url=config.WEBHOOK_URL)
updater.bot.set_webhook(config.WEBHOOK_URL)
diff --git a/database/statistics.py b/database/statistics.py
index 656abf6..afe8040 100644
--- a/database/statistics.py
+++ b/database/statistics.py
@@ -63,7 +63,7 @@ def get_user_stats(user_id):
if played_games == 0:
# prevent division by zero errors
- played_games = 1
+ return translate("no_stats")
last_played_formatted = datetime.utcfromtimestamp(last_played).strftime('%d.%m.%y %H:%M')
win_percentage = round(float(won_games) / float(played_games), 4)