diff --git a/README.md b/README.md index 50212f3..d50fda1 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,11 @@ pip install -r requirements.txt * Retrieve your firebase database url * Set up telegram bot via [BotFather](https://t.me/BotFather) * Insert all of them into .env as follows, you can use py dotenv or set it as env variable in your venv +* You can use the same TOKEN for BOT_TOKEN & TEST_TOKEN but I recommend using two different bots for testing and production + ``` .env BOT_TOKEN=your_bot_token +TEST_TOKEN=your_test_token DATABASE_URL=firebase_url GOOGLE_API_EMAIL=google_api_email FIREBASE_JSON=service_account_key @@ -46,19 +49,6 @@ GOOGLE_JSON=service_account_key ``` ### Step 3 -* Run ngrok -``` terminal -ngrok http 5000 -``` -* Copy the link, it should look something like this 'https://
.ap.ngrok.io' -* Set up web hook by opening this link: -``` url -https://api.telegram.org/bot/setwebhook?url=https://
.ap.ngrok.io/webhook -``` -* You should see this: -``` json -{"ok":true,"result":true,"description":"Webhook was set"} -``` * Proceed to project directory and run: ``` python python3.9 test.py @@ -77,7 +67,9 @@ python3.9 test.py /addincome - Add Income Entry -/retrievetransaction - Retrieve transaction from dates +/getdaytransaction - Retrieve transaction from dates + +/getoverall - Retrieve overall transaction for a month /cancel - Cancel Conversation @@ -101,4 +93,4 @@ Bruce Wang: hello@brucewzj.com LinkedIn: [https://www.linkedin.com/in/brucewzj/](https://www.linkedin.com/in/brucewzj/) -Project Link: [https://github.com/brucewzj99/tele-tracker](https://github.com/brucewzj99/tele-tracker) +Project Link: [https://github.com/brucewzj99/tele-tracker-v2](https://github.com/brucewzj99/tele-tracker-v2) diff --git a/bot/common.py b/bot/common.py index 8df3b05..0b20b61 100644 --- a/bot/common.py +++ b/bot/common.py @@ -26,8 +26,9 @@ class ConversationState(Enum): CONFIG_SUBCATEGORY, CONFIG_PAYMENT, CONFIG_SUBPAYMENT, - HANDLE_RETRIEVE_TRANSACTION, + HANDLE_GET_TRANSACTION, + HANDLE_GET_OVERALL, INCOME, WORK_PLACE, CPF, - ) = range(22) + ) = range(23) diff --git a/bot/google_sheet.py b/bot/google_sheet.py index 16058cb..449a6b7 100644 --- a/bot/google_sheet.py +++ b/bot/google_sheet.py @@ -22,6 +22,7 @@ payment_main_range = "Dropdown!A12:J12" quick_others_range = "Tracker!I3:J13" income_range = "Dropdown!L2:L9" +overall_range = "!M13:O25" def get_main_dropdown_value(sheet_id, entry_type): @@ -266,7 +267,7 @@ def get_quick_add_others(sheet_id): return others_list -def retrieve_transaction(sheet_id, month, date): +def get_day_transaction(sheet_id, month, date): result = ( sheets_api.spreadsheets() .values() @@ -353,3 +354,12 @@ def update_income(sheet_id, month, row_data): body=body_r, ).execute() return True + +def get_overall(sheet_id, month): + result = ( + sheets_api.spreadsheets() + .values() + .get(spreadsheetId=sheet_id, range=f"{month}{overall_range}") + .execute() + ) + return result.get("values", []) \ No newline at end of file diff --git a/bot/telegram_bot.py b/bot/telegram_bot.py index ae45987..e7eca28 100644 --- a/bot/telegram_bot.py +++ b/bot/telegram_bot.py @@ -37,6 +37,10 @@ def check_date_format(date_string): pattern = r"\b\d{1,2}\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b" return bool(re.fullmatch(pattern, date_string, re.IGNORECASE)) +def check_month_format(month_string): + pattern = r"^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$" + return bool(re.fullmatch(pattern, month_string, re.IGNORECASE)) + def get_category_text(sheet_id, entry_type): msg = "" @@ -608,26 +612,36 @@ def help(update, context): update.message.reply_text(HELP_TEXT) -def retrieve_transaction(update, context): +def get_day_transaction(update, context): context.user_data.clear() telegram_id = update.effective_user.id try: context.user_data["sheet_id"] = db.get_user_sheet_id(telegram_id) - update.message.reply_text(RETRIEVE_TRANSACTION_TEXT) - return CS.HANDLE_RETRIEVE_TRANSACTION + update.message.reply_text(GET_TRANSACTION_TEXT) + return CS.HANDLE_GET_TRANSACTION except Exception as e: update.message.reply_text(ERROR_TEXT) return ConversationHandler.END +def get_overall(update, context): + context.user_data.clear() + telegram_id = update.effective_user.id + try: + context.user_data["sheet_id"] = db.get_user_sheet_id(telegram_id) + update.message.reply_text(GET_OVERALL_TEXT) + return CS.HANDLE_GET_OVERALL + except Exception as e: + update.message.reply_text(ERROR_TEXT) + return ConversationHandler.END -def handle_retrieve_transaction(update, context): +def handle_get_transaction(update, context): sheet_id = context.user_data["sheet_id"] reply = update.message.text msg = "" try: if check_date_format(reply): day, month = reply.split(" ") - total_spend, transport_values, other_values = gs.retrieve_transaction( + total_spend, transport_values, other_values = gs.get_day_transaction( sheet_id, month, day ) if not total_spend: @@ -643,11 +657,32 @@ def handle_retrieve_transaction(update, context): update.message.reply_text(msg) return ConversationHandler.END else: - update.message.reply_text(RETRIEVE_TRANSACTION_TEXT) - return CS.HANDLE_RETRIEVE_TRANSACTION + update.message.reply_text(GET_TRANSACTION_TEXT) + return CS.HANDLE_GET_TRANSACTION except Exception as e: update.message.reply_text(ERROR_TEXT) +def handle_get_overall(update, context): + sheet_id = context.user_data["sheet_id"] + month = update.message.text + msg = "" + try: + if check_month_format(month): + values = gs.get_overall(sheet_id, month) + msg = "```\n" + for row in values: + if len(row) == 3: + msg += "{:<20} {:<10} {:<10}\n".format(*row) + elif len(row) == 2: + msg += "{:<20} {:<10}\n".format(*row) + msg += "```" + update.message.reply_text(msg, parse_mode='Markdown') + return ConversationHandler.END + else: + update.message.reply_text(GET_OVERALL_TEXT) + return CS.HANDLE_GET_OVERALL + except Exception as e: + update.message.reply_text(ERROR_TEXT) def add_income(update, context): context.user_data.clear() @@ -749,9 +784,12 @@ def setup_handlers(dispatcher): } # Retrieve transaction-related states and handlers - retrieve_transaction_states = { - CS.HANDLE_RETRIEVE_TRANSACTION: [ - MessageHandler(Filters.text & ~Filters.command, handle_retrieve_transaction) + get_transaction_states = { + CS.HANDLE_GET_TRANSACTION: [ + MessageHandler(Filters.text & ~Filters.command, handle_get_transaction) + ], + CS.HANDLE_GET_OVERALL: [ + MessageHandler(Filters.text & ~Filters.command, handle_get_overall) ], } @@ -768,7 +806,8 @@ def setup_handlers(dispatcher): CommandHandler("addtransport", add_transport), CommandHandler("addothers", add_others), CommandHandler("addincome", add_income), - CommandHandler("retrievetransaction", retrieve_transaction), + CommandHandler("getdaytransaction", get_day_transaction), + CommandHandler("getoverall", get_overall) ], states={ CS.SET_UP: [MessageHandler(Filters.text & ~Filters.command, set_up)], @@ -776,7 +815,7 @@ def setup_handlers(dispatcher): **config_states, **entry_states, **quick_add_states, - **retrieve_transaction_states, + **get_transaction_states, **add_income_states, }, fallbacks=[CommandHandler("cancel", cancel)], diff --git a/bot/text_str.py b/bot/text_str.py index 6925e22..354e324 100644 --- a/bot/text_str.py +++ b/bot/text_str.py @@ -52,16 +52,18 @@ + "/addtransport - Quick Add Transport Entry\n" + "/addothers - Quick Add Other Entry\n" + "/addincome - Add Income Entry\n" - + "/retrievetransaction - Retrieve transaction from dates\n" + + "/getdaytransaction - Retrieve transaction from dates\n" + + "/getoverall - Retrieve overall transaction for a month\n" + "/cancel - Cancel Conversation\n" + "\nTo report bugs, please create a issue at https://github.com/brucewzj99/tele-tracker-v2/issues or contact me @bruceeew on Telegram" ) -RETRIEVE_TRANSACTION_TEXT = "Please specify the date and month you wish to retrieve from in this format: DD MMM\ne.g 16 Mar\nor use /cancel to exit" +GET_TRANSACTION_TEXT = "Please specify the date and month you wish to retrieve from in this format: DD MMM\ne.g 16 Mar\nor use /cancel to exit" +GET_OVERALL_TEXT = "Please specify the month you wish to retrieve your overall transaction in this format: MMM\ne.g Mar\nor use /cancel to exit" ADD_INCOME_TEXT = "Add income\nPlease state your income followed by any remarks (optional): [income],[remarks]\ne.g. 2000, Something" ADD_INCOME_RETRY_TEXT = ( - "Please follow this format: [income],[remarks]\ne.g. 2000, Something" + "Please follow this format:\n[income],[remarks]\ne.g. 2000, Something" ) CHOOSE_INCOME_SOURCE_TEXT = "Please choose your income source" CPF_TEXT = "Is there CPF?" diff --git a/release_notes.md b/release_notes.md index ba3cbc0..4521888 100644 --- a/release_notes.md +++ b/release_notes.md @@ -49,4 +49,14 @@ ## Version 2.0.2 - Date 1 Jun 2023 ### Bug Fix 🛠️ -- Day 1 sum creation bug \ No newline at end of file +- Day 1 sum creation bug + +## Version 2.1.0 - Date 1 Jun 2023 +### New Features 🆕 +- Added get overall functions + +### Enhancement 🔥 +- Rename retrievetransaction to getdaytransaction + +### For Developer 🧑‍💻 +- When you run test.py, ngrok will auto setup with the correct webhook! \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 7562a9f..cebca6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ google-api-python-client==2.86.0 google-auth==2.17.3 google-auth-httplib2==0.1.0 pytz==2023.3 -firebase-admin==6.1.0 \ No newline at end of file +firebase-admin==6.1.0 +pyngrok==6.0.0 \ No newline at end of file diff --git a/test.py b/test.py index ca74594..df94bd2 100644 --- a/test.py +++ b/test.py @@ -3,26 +3,26 @@ from flask import Flask, request import os from bot.telegram_bot import setup_handlers +from pyngrok import ngrok TOKEN = os.environ.get("TEST_TOKEN") app = Flask(__name__) updater = Updater(token=TOKEN) dispatcher = updater.dispatcher - @app.route("/webhook", methods=["POST"]) def webhook(): update = Update.de_json(request.get_json(), updater.bot) dispatcher.process_update(update) return "OK" - @app.route("/") def index(): return "Bot is running!" - -setup_handlers(dispatcher) # Call function to set up bot handlers +setup_handlers(dispatcher) if __name__ == "__main__": - app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000))) + public_url = ngrok.connect(5000, "http").public_url + updater.bot.set_webhook(url=f"{public_url}/webhook") + app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000))) \ No newline at end of file