all repos — groupgardenbot @ a2c0ec4a606eda2ed03baab9f3c5aa3d140832a8

An extension of the game "botany", originally designed for unix-based systems, to the Telegram Bot API.

various bug fixes and improvements
Marco Andronaco andronacomarco@gmail.com
Wed, 16 Aug 2023 19:48:26 +0200
commit

a2c0ec4a606eda2ed03baab9f3c5aa3d140832a8

parent

6240c1d5461e9f1185ae835be26caa0c059a2702

M main.pymain.py

@@ -1,19 +1,25 @@

-import os, logging, time +import os, logging +from datetime import datetime from dotenv import load_dotenv from telegram import Update, User, InlineKeyboardMarkup, InlineKeyboardButton from telegram.ext import PersistenceInput, ApplicationBuilder, CallbackContext, CallbackQueryHandler, CommandHandler, PicklePersistence +from telegram.error import BadRequest from Gardening import Plant logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) +logger = logging.getLogger(__name__) load_dotenv() async def reply(update: Update, context: CallbackContext, text: str = "", markup: str = ""): return await context.bot.send_message(chat_id=update.effective_chat.id, text=text, reply_markup=markup, parse_mode='Markdown') async def edit(update: Update, context: CallbackContext, text: str = "", markup: str = ""): - return await context.bot.editMessageText(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id, text=text, reply_markup=markup, parse_mode='Markdown') + try: + return await context.bot.editMessageText(chat_id=update.effective_chat.id, message_id=update.effective_message.message_id, text=text, reply_markup=markup, parse_mode='Markdown') + except BadRequest: + logger.warning("Message contents were unchanged.") def get_plant_info(plant: Plant): - return f''' + status = f''' ```{plant.get_art()} owner : {plant.owner_name} name : {plant.name}

@@ -21,11 +27,15 @@ stage : {plant.parse_plant()}

age : {plant.age_days} days score : {plant.points} bonus : x{plant.generation_bonus - 1:.2f} -water : {plant.get_water()}``` +last : {datetime.fromtimestamp(plant.last_water).strftime("%d/%m/%Y %H:%M:%S")} +water : {plant.get_water()} +``` {plant.get_description()} -{f'Last watered by {plant.last_water_name}.' if plant.last_water_user != plant.owner else ""} ''' + if plant.last_water_user != plant.owner: + status += f'Last watered by {plant.last_water_name}.' + return status def get_plant(context: CallbackContext, user_id: int): try:

@@ -36,33 +46,53 @@

plant.update() return plant -def get_plant_markup(user_id: int): - return InlineKeyboardMarkup([ - [ - InlineKeyboardButton(text="Innaffia 🚰", callback_data=f"water {user_id}"), - InlineKeyboardButton(text="Aggiorna 🌱", callback_data=f"show {user_id}"), +def get_plant_markup(user_id: int, plant): + + buttons = [] + if not plant.dead: + buttons += [ + [ + InlineKeyboardButton(text="Innaffia 🚰", callback_data=f"water {user_id}"), + InlineKeyboardButton(text="Aggiorna 🌱", callback_data=f"show {user_id}"), + ] ] - ]) + + if plant.dead or plant.stage == 5: + buttons += [ [ InlineKeyboardButton(text="Ricomincia 🌰", callback_data=f"start {user_id}") ] ] + + return InlineKeyboardMarkup(buttons) + +def new_plant(context: CallbackContext, who: User): + plant = Plant(who) + context.bot_data[who.id] = { "plant": plant } + return plant + +def start(context: CallbackContext, user_id: int, who: User): + + plant = get_plant(context, user_id) + new_text = "Hai piantato un nuovo seme!" + if plant is not None: + if not (plant.dead or plant.stage == 5): + return "La tua pianta non è ancora pronta per andarsene!", False + + plant.start_over(who) + return new_text, True + + new_plant(context, who) + return new_text, True + async def start_handler(update: Update, context: CallbackContext): user_id = update.effective_user.id plant = get_plant(context, user_id) - new = False - - if plant is None: - plant = Plant(update.effective_user) - context.bot_data[user_id] = { "plant" : plant } - new = True + + response, new = start(context, update.effective_user.id, update.effective_user) + + await reply(update, context, response) - if plant.dead or plant.stage == 5: - plant.start_over(update.effective_user) - new = True - if new: - show_handler(update, context) - return await reply(update, context, "Hai piantato un nuovo seme! Adesso usa /water o un tasto sopra per innaffiarlo.") - - return await reply(update, context, "La tua pianta non è ancora pronta per andarsene!") + text, markup = show(context, user_id) + await reply(update, context, text, markup) def water(context: CallbackContext, user_id: int, who: User): plant = get_plant(context, user_id)

@@ -83,7 +113,7 @@ if plant is None:

return "Non hai nessuna pianta da mostrare! Usa /start per piantarne una.", "" text = get_plant_info(plant) - markup = get_plant_markup(user_id) + markup = get_plant_markup(user_id, plant) return text, markup def rename(context: CallbackContext, user_id: int):

@@ -119,22 +149,46 @@ async def keyboard_handler(update: Update, context: CallbackContext):

query = update.callback_query data = query.data user_id = None + + if data.startswith("start"): + user_id = int(data.split(" ")[1]) + if user_id != update.effective_user.id: + return await query.answer("Non puoi usare questo comando.") + text, _ = show(context, user_id) + await edit(update, context, text, None) + answer = start(context, user_id, update.effective_user) + await query.answer(answer) + text, markup = show(context, user_id) + return await reply(update, context, text, markup) if data.startswith("water"): user_id = int(data.split(" ")[1]) answer = water(context, user_id, update.effective_user) await query.answer(answer) + text, markup = show(context, user_id) + return await edit(update, context, text, markup) if data.startswith("show"): user_id = int(data.split(" ")[1]) await query.answer() - - if user_id is not None: text, markup = show(context, user_id) return await edit(update, context, text, markup) return await query.answer("Questo tasto non fa nulla.") +async def kill_handler(update: Update, context: CallbackContext): + user_id = update.effective_user.id + plant = get_plant(context, user_id) + plant.dead = True + return await reply(update, context, "πŸ’€πŸ’€πŸ’€", "") + +async def bloom_handler(update: Update, context: CallbackContext): + user_id = update.effective_user.id + plant = get_plant(context, user_id) + plant.points = 9999999 + plant.dead = False + return await reply(update, context, "🌸🌸🌸", "") + if __name__ == "__main__": pers = PersistenceInput(bot_data=True, user_data=False, callback_data=False, chat_data=False)

@@ -145,11 +199,14 @@ application = application.build()

application.add_handler(CallbackQueryHandler(callback=keyboard_handler)) - application.add_handler(CommandHandler('start', start_handler)) application.add_handler(CommandHandler('water', water_handler)) application.add_handler(CommandHandler('show', show_handler)) application.add_handler(CommandHandler('rename', rename_handler)) + + if os.getenv("cheats") == "True": + application.add_handler(CommandHandler('kill', kill_handler)) + application.add_handler(CommandHandler('bloom', bloom_handler)) #print(application.bot.name, "is up and running!") application.run_polling()
A poetry.lock

@@ -0,0 +1,153 @@

+# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "anyio" +version = "3.7.1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (<0.22)"] + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "0.17.3" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, + {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, +] + +[package.dependencies] +anyio = ">=3.0,<5.0" +certifi = "*" +h11 = ">=0.13,<0.15" +sniffio = "==1.*" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx" +version = "0.24.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.7" +files = [ + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, +] + +[package.dependencies] +certifi = "*" +httpcore = ">=0.15.0,<0.18.0" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-telegram-bot" +version = "20.4" +description = "We have made you a wrapper you can't refuse" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-telegram-bot-20.4.tar.gz", hash = "sha256:a6ac3f9c9674aaf7d1c7e652d8b75cde969fb872f75e9521b8516eceaba82b1b"}, + {file = "python_telegram_bot-20.4-py3-none-any.whl", hash = "sha256:e426404b0006989a5bcc05e11a7ef3ffe0c086b684a4e963db5bda1d361a049a"}, +] + +[package.dependencies] +httpx = ">=0.24.1,<0.25.0" + +[package.extras] +all = ["APScheduler (>=3.10.1,<3.11.0)", "aiolimiter (>=1.1.0,<1.2.0)", "cachetools (>=5.3.1,<5.4.0)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.2,<7.0)"] +callback-data = ["cachetools (>=5.3.1,<5.4.0)"] +ext = ["APScheduler (>=3.10.1,<3.11.0)", "aiolimiter (>=1.1.0,<1.2.0)", "cachetools (>=5.3.1,<5.4.0)", "pytz (>=2018.6)", "tornado (>=6.2,<7.0)"] +http2 = ["httpx[http2]"] +job-queue = ["APScheduler (>=3.10.1,<3.11.0)", "pytz (>=2018.6)"] +passport = ["cryptography (>=39.0.1)"] +rate-limiter = ["aiolimiter (>=1.1.0,<1.2.0)"] +socks = ["httpx[socks]"] +webhooks = ["tornado (>=6.2,<7.0)"] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "385c9b021f3f6a003f9788931ee7667f92df82a35bb1ceb36edfdab3d562c0ea"
A pyproject.toml

@@ -0,0 +1,17 @@

+[tool.poetry] +name = "groupgardenbot" +version = "0.1.0" +description = "An extension of the game \"botany\", originally designed for unix-based systems, to the Telegram Bot API." +authors = ["Marco Andronaco <andronacomarco@gmail.com>"] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +python-dotenv = "^1.0.0" +python-telegram-bot = "^20.4" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api"
M requirements.txtrequirements.txt

@@ -1,2 +1,27 @@

-python-dotenv==0.21.1 -python-telegram-bot==20.1 +anyio==3.7.1 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780 \ + --hash=sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5 +certifi==2023.7.22 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 +h11==0.14.0 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ + --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 +httpcore==0.17.3 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888 \ + --hash=sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87 +httpx==0.24.1 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd \ + --hash=sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd +idna==3.4 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ + --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 +python-dotenv==1.0.0 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \ + --hash=sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a +python-telegram-bot==20.4 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:a6ac3f9c9674aaf7d1c7e652d8b75cde969fb872f75e9521b8516eceaba82b1b \ + --hash=sha256:e426404b0006989a5bcc05e11a7ef3ffe0c086b684a4e963db5bda1d361a049a +sniffio==1.3.0 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ + --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384