From 1fe0b315744f41c4624823db151b012e3d8254db Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Mon, 18 Oct 2021 23:55:18 -0400 Subject: [PATCH 01/56] rafactor: Modularize code.py and Indentation fix --- .gitignore | 6 + code/__init__.py | 1 - code/add.py | 74 ++++++ code/code.py | 376 ++++------------------------ code/delete.py | 23 ++ code/display.py | 79 ++++++ code/edit.py | 115 +++++++++ code/expense_record.json | 4 +- code/helper.py | 84 +++++++ code/history.py | 21 ++ setup.py | 4 +- test/test_start_and_menu_command.py | 9 +- 12 files changed, 454 insertions(+), 342 deletions(-) create mode 100644 code/add.py create mode 100644 code/delete.py create mode 100644 code/display.py create mode 100644 code/edit.py create mode 100644 code/helper.py create mode 100644 code/history.py diff --git a/.gitignore b/.gitignore index b6e47617d..507090ef0 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,9 @@ dmypy.json # Pyre type checker .pyre/ + +# Mac Sys files +.DS_Store + +# Generated files +expense_record.json diff --git a/code/__init__.py b/code/__init__.py index e1fbe6e18..63fa0f3e9 100644 --- a/code/__init__.py +++ b/code/__init__.py @@ -5,4 +5,3 @@ @author: deekay """ - diff --git a/code/add.py b/code/add.py new file mode 100644 index 000000000..ef02e1dc3 --- /dev/null +++ b/code/add.py @@ -0,0 +1,74 @@ +import helper +from telebot import types +from datetime import datetime + +option = {} + + +def run(message, bot): + helper.read_json() + chat_id = message.chat.id + option.pop(chat_id, None) # remove temp choice + markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) + markup.row_width = 2 + for c in helper.getSpendCategories(): + markup.add(c) + msg = bot.reply_to(message, 'Select Category', reply_markup=markup) + bot.register_next_step_handler(msg, post_category_selection, bot) + + +def post_category_selection(message, bot): + try: + chat_id = message.chat.id + selected_category = message.text + if selected_category not in helper.getSpendCategories(): + bot.send_message(chat_id, 'Invalid', reply_markup=types.ReplyKeyboardRemove()) + raise Exception("Sorry I don't recognise this category \"{}\"!".format(selected_category)) + + option[chat_id] = selected_category + message = bot.send_message(chat_id, 'How much did you spend on {}? \n(Enter numeric values only)'.format(str(option[chat_id]))) + bot.register_next_step_handler(message, post_amount_input, bot) + except Exception as e: + bot.reply_to(message, 'Oh no! ' + str(e)) + display_text = "" + commands = helper.getCommands() + for c in commands: # generate help text out of the commands dictionary defined at the top + display_text += "/" + c + ": " + display_text += commands[c] + "\n" + bot.send_message(chat_id, 'Please select a menu option from below:') + bot.send_message(chat_id, display_text) + + +def post_amount_input(message, bot): + try: + chat_id = message.chat.id + amount_entered = message.text + amount_value = helper.validate_entered_amount(amount_entered) # validate + if amount_value == 0: # cannot be $0 spending + raise Exception("Spent amount has to be a non-zero number.") + + date_of_entry = datetime.today().strftime(helper.getDateFormat() + ' ' + helper.getTimeFormat()) + date_str, category_str, amount_str = str(date_of_entry), str(option[chat_id]), str(amount_value) + helper.write_json(add_user_record(chat_id, "{},{},{}".format(date_str, category_str, amount_str))) + bot.send_message(chat_id, 'The following expenditure has been recorded: You have spent ${} for {} on {}'.format(amount_str, category_str, date_str)) + + except Exception as e: + print() + print() + print() + print() + print("blah blah.....") + print() + print() + print() + print() + bot.reply_to(message, 'Oh no. ' + str(e)) + + +def add_user_record(chat_id, record_to_be_added): + user_list = {} + if not (str(chat_id) in user_list): + user_list[str(chat_id)] = [] + + user_list[str(chat_id)].append(record_to_be_added) + return user_list diff --git a/code/code.py b/code/code.py index 7273ef23d..00e6e053c 100644 --- a/code/code.py +++ b/code/code.py @@ -1,385 +1,92 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - -import json import logging -import re -import os import telebot import time -from telebot import types -from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton +import helper +import edit +import history +import display +import delete +import add from datetime import datetime -api_token = "INSERT API KEY HERE" - -dateFormat = '%d-%b-%Y' -timeFormat = '%H:%M' -monthFormat = '%b-%Y' +api_token = "2058952091:AAGVtSVBKT1AnjTpNyojdNz4sgD68pY3mzM" -#global variables to store user choice, user list, spend categories, etc -option = {} +# global variables to store user choice, user list, spend categories, etc user_list = {} -spend_categories = ['Food', 'Groceries', 'Utilities', 'Transport', 'Shopping', 'Miscellaneous'] -spend_display_option = ['Day', 'Month'] - -#set of implemented commands and their description -commands = { - 'menu': 'Display this menu', - 'add': 'Record/Add a new spending', - 'display': 'Show sum of expenditure for the current day/month', - 'history': 'Display spending history', - 'delete': 'Clear/Erase all your records', - 'edit': 'Edit/Change spending details' -} bot = telebot.TeleBot(api_token) -telebot.logger.setLevel(logging.INFO) +telebot.logger.setLevel(logging.DEBUG) -#Define listener for requests by user +option = {} + + +# Define listener for requests by user def listener(user_requests): - for req in user_requests: - if(req.content_type=='text'): - print("{} name:{} chat_id:{} \nmessage: {}\n".format(str(datetime.now()),str(req.chat.first_name),str(req.chat.id),str(req.text))) + for req in user_requests: + if(req.content_type == 'text'): + print("{} name:{} chat_id:{} \nmessage: {}\n".format(str(datetime.now()), str(req.chat.first_name), str(req.chat.id), str(req.text))) bot.set_update_listener(listener) -#defines how the /start and /help commands have to be handled/processed + +# defines how the /start and /help commands have to be handled/processed @bot.message_handler(commands=['start', 'menu']) def start_and_menu_command(m): - read_json() + helper.read_json() global user_list chat_id = m.chat.id text_intro = "Welcome to TrackMyDollar - a simple solution to track your expenses! \nHere is a list of available commands, please enter a command of your choice so that I can assist you further: \n\n" + commands = helper.getCommands() for c in commands: # generate help text out of the commands dictionary defined at the top text_intro += "/" + c + ": " text_intro += commands[c] + "\n\n" bot.send_message(chat_id, text_intro) return True -#defines how the /new command has to be handled/processed + +# defines how the /new command has to be handled/processed @bot.message_handler(commands=['add']) def command_add(message): - read_json() - chat_id = message.chat.id - option.pop(chat_id, None) # remove temp choice - markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) - markup.row_width = 2 - for c in spend_categories: - markup.add(c) - msg = bot.reply_to(message, 'Select Category', reply_markup=markup) - bot.register_next_step_handler(msg, post_category_selection) - -def post_category_selection(message): - try: - chat_id = message.chat.id - selected_category = message.text - if not selected_category in spend_categories: - msg = bot.send_message(chat_id, 'Invalid', reply_markup=types.ReplyKeyboardRemove()) - raise Exception("Sorry I don't recognise this category \"{}\"!".format(selected_category)) - - option[chat_id] = selected_category - message = bot.send_message(chat_id, 'How much did you spend on {}? \n(Enter numeric values only)'.format(str(option[chat_id]))) - bot.register_next_step_handler(message, post_amount_input) - except Exception as e: - bot.reply_to(message, 'Oh no! ' + str(e)) - display_text = "" - for c in commands: # generate help text out of the commands dictionary defined at the top - display_text += "/" + c + ": " - display_text += commands[c] + "\n" - bot.send_message(chat_id, 'Please select a menu option from below:') - bot.send_message(chat_id, display_text) - -def post_amount_input(message): - try: - chat_id = message.chat.id - amount_entered = message.text - amount_value = validate_entered_amount(amount_entered) # validate - if amount_value == 0: # cannot be $0 spending - raise Exception("Spent amount has to be a non-zero number.") - - date_of_entry = datetime.today().strftime(dateFormat + ' ' + timeFormat) - date_str, category_str, amount_str = str(date_of_entry), str(option[chat_id]), str(amount_value) - write_json(add_user_record(chat_id, "{},{},{}".format(date_str, category_str, amount_str))) - bot.send_message(chat_id, 'The following expenditure has been recorded: You have spent ${} for {} on {}'.format(amount_str, category_str, date_str)) - - except Exception as e: - bot.reply_to(message, 'Oh no. ' + str(e)) + add.run(message, bot) -def validate_entered_amount(amount_entered): - if len(amount_entered) > 0 and len(amount_entered) <= 15: - if amount_entered.isdigit: - if re.match("^[0-9]*\\.?[0-9]*$", amount_entered): - amount = round(float(amount_entered), 2) - if amount > 0: - return str(amount) - return 0 -def write_json(user_list): - try: - with open('expense_record.json', 'w') as json_file: - json.dump(user_list, json_file, ensure_ascii=False, indent=4) - except FileNotFoundError: - print('Sorry, the data file could not be found.') - -def add_user_record(chat_id, record_to_be_added): - global user_list - if not (str(chat_id) in user_list): - user_list[str(chat_id)] = [] - - user_list[str(chat_id)].append(record_to_be_added) - return user_list - -#function to load .json expense record data -def read_json(): - global user_list - try: - if os.stat('expense_record.json').st_size!=0: - with open('expense_record.json') as expense_record: - expense_record_data = json.load(expense_record) - user_list = expense_record_data - - except FileNotFoundError: - print("---------NO RECORDS FOUND---------") - - -#function to fetch expenditure history of the user +# function to fetch expenditure history of the user @bot.message_handler(commands=['history']) -def show_history(message): - try: - read_json() - chat_id=message.chat.id - user_history=getUserHistory(chat_id) - spend_total_str = "" - if user_history is None: - raise Exception("Sorry! No spending records found!") - spend_history_str = "Here is your spending history : \nDATE, CATEGORY, AMOUNT\n----------------------\n" - if len(user_history)==0: - spend_total_str = "Sorry! No spending records found!" - else: - for rec in user_history: - spend_total_str += str(rec) + "\n" - bot.send_message(chat_id, spend_total_str) - except Exception as e: - bot.reply_to(message, "Oops!" + str(e)) - +def command_history(message): + history.run(message, bot) -#function to edit date, category or cost of a transaction -@bot.message_handler(commands=['edit']) -def edit1(m): - read_json() - global user_list - chat_id = m.chat.id - - if (str(chat_id) in user_list): - info = bot.reply_to(m, "Please enter the date and category of the transaction you made (Eg: 01-Mar-2021,Transport)") - bot.register_next_step_handler(info, edit2) - - else: - bot.reply_to(chat_id, "No data found") -i_edit = -1 -def edit2(m): - global i_edit - i_edit = -1 - chat_id = m.chat.id - data_edit = getUserHistory(chat_id) - info = m.text - date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" - info = info.split(',') - x = re.search(date_format,info[0]) - if(x == None): - bot.reply_to(m, "The date is incorrect") - return - - markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) - markup.row_width = 2 - choices = ['Date','Category','Cost'] - for c in choices: - markup.add(c) - - for record in data_edit: - i_edit = i_edit + 1 - record = record.split(',') - if info[0] == record[0][0:11] and info[1] == record[1]: - choice = bot.reply_to(m, "What do you want to update?", reply_markup = markup) - bot.register_next_step_handler(choice, edit3) - break - -def edit3(m): - choice1 = m.text - chat_id = m.chat.id - data_edit = getUserHistory(chat_id) - markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) - markup.row_width = 2 - for cat in spend_categories: - markup.add(cat) - if(choice1 == 'Date'): - new_date = bot.reply_to(m, "Please enter the new date (in dd-mmm-yyy format)") - bot.register_next_step_handler(new_date, edit_date) - - - if(choice1 == 'Category'): - new_cat = bot.reply_to(m, "Please select the new category", reply_markup = markup) - bot.register_next_step_handler(new_cat, edit_cat) - - - if(choice1 == 'Cost'): - new_cost = bot.reply_to(m, "Please type the new cost") - bot.register_next_step_handler(new_cost, edit_cost) - -def edit_date(m): - global i_edit - new_date = m.text - date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" - chat_id = m.chat.id - data_edit = getUserHistory(chat_id) - x1 = re.search(date_format,new_date) - if(x1 == None): - bot.reply_to(m, "The date is incorrect") - return - record = data_edit[i_edit].split(',') - record[0] = new_date + record[0][11:len(record[0])] - data_edit[i_edit] = record[0] + ',' + record[1] + ',' + record[2] - user_list[str(chat_id)] = data_edit - write_json(user_list) - bot.reply_to(m, "Date is updated") - -def edit_cat(m): - global i_edit - chat_id = m.chat.id - data_edit = getUserHistory(chat_id) - new_cat = m.text - record = data_edit[i_edit].split(',') - record[1] = new_cat - data_edit[i_edit] = record[0] + ',' + record[1] + ',' + record[2] - user_list[str(chat_id)] = data_edit - write_json(user_list) - bot.reply_to(m, "Category is updated") +# function to edit date, category or cost of a transaction +@bot.message_handler(commands=['edit']) +def command_edit(message): + edit.run(message, bot) -def edit_cost(m): - global i_edit - new_cost = m.text - chat_id = m.chat.id - data_edit = getUserHistory(chat_id) - - if(validate_entered_amount(new_cost) != 0): - record = data_edit[i_edit].split(',') - record[2] = new_cost - data_edit[i_edit] = record[0] + ',' + record[1] + ',' + str(float(record[2])) - user_list[str(chat_id)] = data_edit - write_json(user_list) - bot.reply_to(m, "Cost is updated") - - else: - bot.reply_to(m, "The cost is invalid") - return -#function to display total expenditure +# function to display total expenditure @bot.message_handler(commands=['display']) def command_display(message): - read_json() - chat_id = message.chat.id - history = getUserHistory - if history == None: - bot.send_message(chat_id, "Oops! Looks like you do not have any spending records!") - else: - markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) - markup.row_width = 2 - for mode in spend_display_option: - markup.add(mode) - # markup.add('Day', 'Month') - msg = bot.reply_to(message, 'Please select a category to see the total expense', reply_markup=markup) - bot.register_next_step_handler(msg, display_total) - -def display_total(message): - try: - chat_id = message.chat.id - DayWeekMonth = message.text - - if not DayWeekMonth in spend_display_option: - raise Exception("Sorry I can't show spendings for \"{}\"!".format(DayWeekMonth)) - - history = getUserHistory(chat_id) - if history is None: - raise Exception("Oops! Looks like you do not have any spending records!") - - bot.send_message(chat_id, "Hold on! Calculating...") - bot.send_chat_action(chat_id, 'typing') # show the bot "typing" (max. 5 secs) - time.sleep(0.5) - - total_text = "" - - if DayWeekMonth == 'Day': - query = datetime.now().today().strftime(dateFormat) - queryResult = [value for index, value in enumerate(history) if str(query) in value] #query all that contains today's date - elif DayWeekMonth == 'Month': - query = datetime.now().today().strftime(monthFormat) - queryResult = [value for index, value in enumerate(history) if str(query) in value] #query all that contains today's date - total_text = calculate_spendings(queryResult) + display.run(message, bot) - spending_text = "" - if len(total_text) == 0: - spending_text = "You have no spendings for {}!".format(DayWeekMonth) - else: - spending_text = "Here are your total spendings {}:\nCATEGORIES,AMOUNT \n----------------------\n{}".format(DayWeekMonth.lower(), total_text) - bot.send_message(chat_id, spending_text) - except Exception as e: - bot.reply_to(message, str(e)) - -def calculate_spendings(queryResult): - total_dict = {} - - for row in queryResult: - s = row.split(',') #date,cat,money - cat = s[1] #cat - if cat in total_dict: - total_dict[cat] = round(total_dict[cat] + float(s[2]),2) #round up to 2 decimal - else: - total_dict[cat] = float(s[2]) - total_text = "" - for key, value in total_dict.items(): - total_text += str(key) + " $" + str(value) + "\n" - return total_text - -def getUserHistory(chat_id): - global user_list - if (str(chat_id) in user_list): - return user_list[str(chat_id)] - return None +# handles "/delete" command +@bot.message_handler(commands=['delete']) +def command_delete(message): + delete.run(message, bot) -#function to delete a record -def deleteHistory(chat_id): +# not used +def addUserHistory(chat_id, user_record): global user_list - if (str(chat_id) in user_list): - del user_list[str(chat_id)] + if(not(str(chat_id) in user_list)): + user_list[str(chat_id)] = [] + user_list[str(chat_id)].append(user_record) return user_list -#handles "/delete" command -@bot.message_handler(commands=['delete']) -def command_delete(message): - global user_list - chat_id = message.chat.id - read_json() - delete_history_text = "" - if (str(chat_id) in user_list): - write_json(deleteHistory(chat_id)) - delete_history_text = "History has been deleted!" - else: - delete_history_text = "No records there to be deleted. Start adding your expenses to keep track of your spendings!" - bot.send_message(chat_id, delete_history_text) - -def addUserHistory(chat_id, user_record): - global user_list - if(not(str(chat_id) in user_list)): - user_list[str(chat_id)]=[] - user_list[str(chat_id)].append(user_record) - return user_list def main(): try: @@ -388,5 +95,6 @@ def main(): time.sleep(3) print("Connection Timeout") + if __name__ == '__main__': main() diff --git a/code/delete.py b/code/delete.py new file mode 100644 index 000000000..a1041a61f --- /dev/null +++ b/code/delete.py @@ -0,0 +1,23 @@ +import helper + + +def run(message, bot): + global user_list + chat_id = message.chat.id + helper.read_json() + delete_history_text = "" + user_list = helper.getUserHistory() + if (str(chat_id) in user_list): + helper.write_json(deleteHistory(chat_id)) + delete_history_text = "History has been deleted!" + else: + delete_history_text = "No records there to be deleted. Start adding your expenses to keep track of your spendings!" + bot.send_message(chat_id, delete_history_text) + + +# function to delete a record +def deleteHistory(chat_id): + global user_list + if (str(chat_id) in user_list): + del user_list[str(chat_id)] + return user_list diff --git a/code/display.py b/code/display.py new file mode 100644 index 000000000..832fdf521 --- /dev/null +++ b/code/display.py @@ -0,0 +1,79 @@ +import time +import helper +from telebot import types +from datetime import datetime + + +def run(message, bot): + helper.read_json() + chat_id = message.chat.id + history = helper.getUserHistory(chat_id) + if history is None: + bot.send_message(chat_id, "Oops! Looks like you do not have any spending records!") + else: + markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) + markup.row_width = 2 + for mode in helper.getSpendDisplayOptions(): + markup.add(mode) + # markup.add('Day', 'Month') + msg = bot.reply_to(message, 'Please select a category to see the total expense', reply_markup=markup) + bot.register_next_step_handler(msg, display_total, bot) + + +def display_total(message, bot): + try: + chat_id = message.chat.id + DayWeekMonth = message.text + + if DayWeekMonth not in helper.getSpendDisplayOptions(): + raise Exception("Sorry I can't show spendings for \"{}\"!".format(DayWeekMonth)) + + history = helper.getUserHistory(chat_id) + if history is None: + raise Exception("Oops! Looks like you do not have any spending records!") + + bot.send_message(chat_id, "Hold on! Calculating...") + # show the bot "typing" (max. 5 secs) + bot.send_chat_action(chat_id, 'typing') + time.sleep(0.5) + + total_text = "" + + if DayWeekMonth == 'Day': + query = datetime.now().today().strftime(helper.getDateFormat()) + # query all that contains today's date + queryResult = [value for index, value in enumerate(history) if str(query) in value] + elif DayWeekMonth == 'Month': + query = datetime.now().today().strftime(helper.getMonthFormat()) + # query all that contains today's date + queryResult = [value for index, value in enumerate(history) if str(query) in value] + total_text = calculate_spendings(queryResult) + + spending_text = "" + if len(total_text) == 0: + spending_text = "You have no spendings for {}!".format(DayWeekMonth) + else: + spending_text = "Here are your total spendings {}:\nCATEGORIES,AMOUNT \n----------------------\n{}".format(DayWeekMonth.lower(), total_text) + + bot.send_message(chat_id, spending_text) + except Exception as e: + bot.reply_to(message, str(e)) + + +def calculate_spendings(queryResult): + total_dict = {} + + for row in queryResult: + # date,cat,money + s = row.split(',') + # cat + cat = s[1] + if cat in total_dict: + # round up to 2 decimal + total_dict[cat] = round(total_dict[cat] + float(s[2]), 2) + else: + total_dict[cat] = float(s[2]) + total_text = "" + for key, value in total_dict.items(): + total_text += str(key) + " $" + str(value) + "\n" + return total_text diff --git a/code/edit.py b/code/edit.py new file mode 100644 index 000000000..23c034c3d --- /dev/null +++ b/code/edit.py @@ -0,0 +1,115 @@ +import re +import helper +from telebot import types + + +def run(m, bot): + helper.read_json() + global user_list + chat_id = m.chat.id + + if (str(chat_id) in user_list): + info = bot.reply_to(m, "Please enter the date and category of the transaction you made (Eg: 01-Mar-2021,Transport)") + bot.register_next_step_handler(info, edit2, bot) + else: + bot.reply_to(chat_id, "No data found") + + +i_edit = -1 + + +def edit2(m, bot): + global i_edit + i_edit = -1 + chat_id = m.chat.id + data_edit = helper.getUserHistory(chat_id) + info = m.text + date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + info = info.split(',') + x = re.search(date_format, info[0]) + if(x is None): + bot.reply_to(m, "The date is incorrect") + return + + markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) + markup.row_width = 2 + choices = ['Date', 'Category', 'Cost'] + for c in choices: + markup.add(c) + + for record in data_edit: + i_edit = i_edit + 1 + record = record.split(',') + if info[0] == record[0][0:11] and info[1] == record[1]: + choice = bot.reply_to(m, "What do you want to update?", reply_markup=markup) + bot.register_next_step_handler(choice, edit3) + break + + +def edit3(m, bot): + choice1 = m.text + markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) + markup.row_width = 2 + for cat in helper.getSpendCategories(): + markup.add(cat) + + if(choice1 == 'Date'): + new_date = bot.reply_to(m, "Please enter the new date (in dd-mmm-yyy format)") + bot.register_next_step_handler(new_date, edit_date) + + if(choice1 == 'Category'): + new_cat = bot.reply_to(m, "Please select the new category", reply_markup=markup) + bot.register_next_step_handler(new_cat, edit_cat) + + if(choice1 == 'Cost'): + new_cost = bot.reply_to(m, "Please type the new cost") + bot.register_next_step_handler(new_cost, edit_cost) + + +def edit_date(m, bot): + global i_edit + new_date = m.text + date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + chat_id = m.chat.id + data_edit = helper.getUserHistory(chat_id) + x1 = re.search(date_format, new_date) + if(x1 is None): + bot.reply_to(m, "The date is incorrect") + return + record = data_edit[i_edit].split(',') + record[0] = new_date + record[0][11:len(record[0])] + data_edit[i_edit] = record[0] + ',' + record[1] + ',' + record[2] + user_list[str(chat_id)] = data_edit + helper.write_json(user_list) + bot.reply_to(m, "Date is updated") + + +def edit_cat(m, bot): + global i_edit + chat_id = m.chat.id + data_edit = helper.getUserHistory(chat_id) + new_cat = m.text + record = data_edit[i_edit].split(',') + record[1] = new_cat + data_edit[i_edit] = record[0] + ',' + record[1] + ',' + record[2] + user_list[str(chat_id)] = data_edit + helper.write_json(user_list) + bot.reply_to(m, "Category is updated") + + +def edit_cost(m, bot): + global i_edit + new_cost = m.text + chat_id = m.chat.id + data_edit = helper.getUserHistory(chat_id) + + if(helper.validate_entered_amount(new_cost) != 0): + record = data_edit[i_edit].split(',') + record[2] = new_cost + data_edit[i_edit] = record[0] + ',' + record[1] + ',' + str(float(record[2])) + user_list[str(chat_id)] = data_edit + helper.write_json(user_list) + bot.reply_to(m, "Cost is updated") + else: + bot.reply_to(m, "The cost is invalid") + return diff --git a/code/expense_record.json b/code/expense_record.json index 9e26dfeeb..0db3279e4 100644 --- a/code/expense_record.json +++ b/code/expense_record.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + +} diff --git a/code/helper.py b/code/helper.py new file mode 100644 index 000000000..8fc6555f0 --- /dev/null +++ b/code/helper.py @@ -0,0 +1,84 @@ +import re +import json +import os + +spend_categories = ['Food', 'Groceries', 'Utilities', 'Transport', 'Shopping', 'Miscellaneous'] + +spend_display_option = ['Day', 'Month'] + +# set of implemented commands and their description +commands = { + 'menu': 'Display this menu', + 'add': 'Record/Add a new spending', + 'display': 'Show sum of expenditure for the current day/month', + 'history': 'Display spending history', + 'delete': 'Clear/Erase all your records', + 'edit': 'Edit/Change spending details' +} + +dateFormat = '%d-%b-%Y' +timeFormat = '%H:%M' +monthFormat = '%b-%Y' + + +# function to load .json expense record data +def read_json(): + global user_list + try: + if os.stat('expense_record.json').st_size != 0: + with open('expense_record.json') as expense_record: + expense_record_data = json.load(expense_record) + user_list = expense_record_data + + except FileNotFoundError: + print("---------NO RECORDS FOUND---------") + + +def write_json(user_list): + try: + with open('expense_record.json', 'a') as json_file: + json.dump(user_list, json_file, ensure_ascii=False, indent=4) + except FileNotFoundError: + print('Sorry, the data file could not be found.') + + +def validate_entered_amount(amount_entered): + if len(amount_entered) > 0 and len(amount_entered) <= 15: + if amount_entered.isdigit: + if re.match("^[0-9]*\\.?[0-9]*$", amount_entered): + amount = round(float(amount_entered), 2) + if amount > 0: + return str(amount) + return 0 + + +# TODO: load from expense_record.json +def getUserHistory(chat_id): + global user_list + if (str(chat_id) in user_list): + return user_list[str(chat_id)] + return None + + +def getSpendCategories(): + return spend_categories + + +def getSpendDisplayOptions(): + return spend_display_option + + +def getCommands(): + return commands + + +def getDateFormat(): + return dateFormat + + +def getTimeFormat(): + return timeFormat + + +def getMonthFormat(): + return monthFormat diff --git a/code/history.py b/code/history.py new file mode 100644 index 000000000..9df759248 --- /dev/null +++ b/code/history.py @@ -0,0 +1,21 @@ +import helper + + +# TODO: check if message is printed properly +def run(message, bot): + try: + helper.read_json() + chat_id = message.chat.id + user_history = helper.getUserHistory(chat_id) + spend_total_str = "" + if user_history is None: + raise Exception("Sorry! No spending records found!") + spend_total_str = "Here is your spending history : \nDATE, CATEGORY, AMOUNT\n----------------------\n" + if len(user_history) == 0: + spend_total_str = "Sorry! No spending records found!" + else: + for rec in user_history: + spend_total_str += str(rec) + "\n" + bot.send_message(chat_id, spend_total_str) + except Exception as e: + bot.reply_to(message, "Oops!" + str(e)) diff --git a/setup.py b/setup.py index 7d61d7880..13d1a58ac 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup,find_packages +from setuptools import setup, find_packages setup( name='Track My Dollar', @@ -7,4 +7,4 @@ author='Dev, Prakruthi, Radhika, Rohan, Sunidhi', scripts=['code/code.py'], packages=find_packages() -) +) diff --git a/test/test_start_and_menu_command.py b/test/test_start_and_menu_command.py index b3789ca01..43057261d 100644 --- a/test/test_start_and_menu_command.py +++ b/test/test_start_and_menu_command.py @@ -6,10 +6,11 @@ @author: deekay """ -import pytest -#from code.code import start_and_menu_command +# import pytest +# from code.code import start_and_menu_command + def test_start_and_menu_command_func(): - #test_result = start_and_menu_command("/start") - #assert True == test_result, "Normal Case" + # test_result = start_and_menu_command("/start") + # assert True == test_result, "Normal Case" print("Hello") From 56ff2e3a1834987cba7bf495f410f40557c726f3 Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Tue, 19 Oct 2021 00:22:53 -0400 Subject: [PATCH 02/56] chore: updated setup.py --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 13d1a58ac..cfa2a2349 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,5 @@ version='1.0', description='An easy to use Telegram Bot to track everyday expenses', author='Dev, Prakruthi, Radhika, Rohan, Sunidhi', - scripts=['code/code.py'], packages=find_packages() ) From 9213d2217dc3c94971239d95511688feee175395 Mon Sep 17 00:00:00 2001 From: ASHOK KUMAR S Date: Tue, 19 Oct 2021 15:23:43 -0400 Subject: [PATCH 03/56] delete expense_record.json --- code/expense_record.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 code/expense_record.json diff --git a/code/expense_record.json b/code/expense_record.json deleted file mode 100644 index 0db3279e4..000000000 --- a/code/expense_record.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} From 475482d3d6cf47b60a492e46d46db663b98e52a0 Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Tue, 19 Oct 2021 20:11:45 -0400 Subject: [PATCH 04/56] fix: Issue while adding and loading from expence_report --- code/add.py | 13 ++----------- code/helper.py | 14 ++++++++------ code/history.py | 1 - 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/code/add.py b/code/add.py index ef02e1dc3..083c537d9 100644 --- a/code/add.py +++ b/code/add.py @@ -53,21 +53,12 @@ def post_amount_input(message, bot): bot.send_message(chat_id, 'The following expenditure has been recorded: You have spent ${} for {} on {}'.format(amount_str, category_str, date_str)) except Exception as e: - print() - print() - print() - print() - print("blah blah.....") - print() - print() - print() - print() bot.reply_to(message, 'Oh no. ' + str(e)) def add_user_record(chat_id, record_to_be_added): - user_list = {} - if not (str(chat_id) in user_list): + user_list = helper.read_json() + if str(chat_id) not in user_list: user_list[str(chat_id)] = [] user_list[str(chat_id)].append(record_to_be_added) diff --git a/code/helper.py b/code/helper.py index 8fc6555f0..a5528db79 100644 --- a/code/helper.py +++ b/code/helper.py @@ -23,12 +23,15 @@ # function to load .json expense record data def read_json(): - global user_list try: - if os.stat('expense_record.json').st_size != 0: + if not os.path.exists('expense_record.json'): + with open('expense_record.json', 'w') as json_file: + json_file.write('{}') + return json.dumps('{}') + elif os.stat('expense_record.json').st_size != 0: with open('expense_record.json') as expense_record: expense_record_data = json.load(expense_record) - user_list = expense_record_data + return expense_record_data except FileNotFoundError: print("---------NO RECORDS FOUND---------") @@ -36,7 +39,7 @@ def read_json(): def write_json(user_list): try: - with open('expense_record.json', 'a') as json_file: + with open('expense_record.json', 'w') as json_file: json.dump(user_list, json_file, ensure_ascii=False, indent=4) except FileNotFoundError: print('Sorry, the data file could not be found.') @@ -52,9 +55,8 @@ def validate_entered_amount(amount_entered): return 0 -# TODO: load from expense_record.json def getUserHistory(chat_id): - global user_list + user_list = read_json() if (str(chat_id) in user_list): return user_list[str(chat_id)] return None diff --git a/code/history.py b/code/history.py index 9df759248..95e9dd9db 100644 --- a/code/history.py +++ b/code/history.py @@ -1,7 +1,6 @@ import helper -# TODO: check if message is printed properly def run(message, bot): try: helper.read_json() From 7bb7dd74745ac37f730993ac2d7d44288b0d4a39 Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 19 Oct 2021 21:15:09 -0400 Subject: [PATCH 05/56] Added exception message code and set logging to info --- code/add.py | 3 +++ code/code.py | 5 +++-- code/display.py | 2 ++ code/history.py | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/code/add.py b/code/add.py index 083c537d9..b6b6308d5 100644 --- a/code/add.py +++ b/code/add.py @@ -1,4 +1,5 @@ import helper +import logging from telebot import types from datetime import datetime @@ -29,6 +30,7 @@ def post_category_selection(message, bot): message = bot.send_message(chat_id, 'How much did you spend on {}? \n(Enter numeric values only)'.format(str(option[chat_id]))) bot.register_next_step_handler(message, post_amount_input, bot) except Exception as e: + logging.exception(str(e)) bot.reply_to(message, 'Oh no! ' + str(e)) display_text = "" commands = helper.getCommands() @@ -53,6 +55,7 @@ def post_amount_input(message, bot): bot.send_message(chat_id, 'The following expenditure has been recorded: You have spent ${} for {} on {}'.format(amount_str, category_str, date_str)) except Exception as e: + logging.exception(str(e)) bot.reply_to(message, 'Oh no. ' + str(e)) diff --git a/code/code.py b/code/code.py index 00e6e053c..f3c119c93 100644 --- a/code/code.py +++ b/code/code.py @@ -18,7 +18,7 @@ bot = telebot.TeleBot(api_token) -telebot.logger.setLevel(logging.DEBUG) +telebot.logger.setLevel(logging.INFO) option = {} @@ -91,7 +91,8 @@ def addUserHistory(chat_id, user_record): def main(): try: bot.polling(none_stop=True) - except Exception: + except Exception as e: + logging.exception(str(e)) time.sleep(3) print("Connection Timeout") diff --git a/code/display.py b/code/display.py index 832fdf521..e6b3e5a9a 100644 --- a/code/display.py +++ b/code/display.py @@ -1,5 +1,6 @@ import time import helper +import logging from telebot import types from datetime import datetime @@ -57,6 +58,7 @@ def display_total(message, bot): bot.send_message(chat_id, spending_text) except Exception as e: + logging.exception(str(e)) bot.reply_to(message, str(e)) diff --git a/code/history.py b/code/history.py index 95e9dd9db..0b7215dc8 100644 --- a/code/history.py +++ b/code/history.py @@ -1,4 +1,5 @@ import helper +import logging def run(message, bot): @@ -17,4 +18,5 @@ def run(message, bot): spend_total_str += str(rec) + "\n" bot.send_message(chat_id, spend_total_str) except Exception as e: + logging.exception(str(e)) bot.reply_to(message, "Oops!" + str(e)) From 8022e48da9594deb2d0718d915ec9fd9cdec550f Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 19 Oct 2021 21:33:57 -0400 Subject: [PATCH 06/56] Created add.md - readme for add.py feature --- docs/add.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/add.md diff --git a/docs/add.md b/docs/add.md new file mode 100644 index 000000000..4f9d3292f --- /dev/null +++ b/docs/add.md @@ -0,0 +1,62 @@ +# About MyDollarBot's /add Feature +This feature enables the user to add a new expense to their expense tracker. +Currently we have the following expense categories set by default: + +- Food +- Groceries +- Utilities +- Transport +- Shopping +- Miscellaneous + +The user can choose a category and add the amount they have spent to be stored in the expense tracker. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/add.py) + +# Code Description +## Functions + +1. run(message, bot): +This is the main function used to implement the add feature. It pop ups a menu on the bot asking the user to choose their expense category, after which control is given to post_category_selection(message, bot) for further proccessing. It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the main code.py function. + +2. post_category_selection(message, bot): + It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the run(message, bot): function in the add.py file. It requests the user to enter the amount they have spent on the expense category chosen and then passes control to post_amount_input(message, bot): for further processing. + +3. post_amount_input(message, bot): + It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the post_category_selection(message, bot): function in the add.py file. It takes the amount entered by the user, validates it with helper.validate() and then calls add_user_record to store it. + +4. add_user_record(chat_id, record_to_be_added): + Takes 2 arguments - **chat_id** or the chat_id of the user's chat, and **record_to_be_added** which is the expense record to be added to the store. It then stores this expense record in the store. + +# How to run this feature? +Once the project is running(please follow the instructions given in the main README.md for this), please type /add into the telegram bot. + +Below you can see an example in text format: + +dollarbot, [19.10.21 21:14] +[In reply to Sri Athithya Kruth] +Select Category + +Sri Athithya Kruth, [19.10.21 21:14] +Food + +dollarbot, [19.10.21 21:14] +How much did you spend on Food? +(Enter numeric values only) + +Sri Athithya Kruth, [19.10.21 21:14] +1212 + +dollarbot, [19.10.21 21:14] +The following expenditure has been recorded: You have spent $1212.0 for Food on 19-Oct-2021 21:14 + +Sri Athithya Kruth, [19.10.21 21:14] +/history + +dollarbot, [19.10.21 21:14] +Here is your spending history : +DATE, CATEGORY, AMOUNT +---------------------- +19-Oct-2021 21:13,Food,10.0 +19-Oct-2021 21:14,Food,1212.0 \ No newline at end of file From 12597ee4e5e856de0d6a01452cf728aff8063afb Mon Sep 17 00:00:00 2001 From: Sri Athithya Kruth Babu Date: Wed, 20 Oct 2021 07:05:08 +0530 Subject: [PATCH 07/56] Removed extra lines in example in add.md --- docs/add.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/add.md b/docs/add.md index 4f9d3292f..5ab83541e 100644 --- a/docs/add.md +++ b/docs/add.md @@ -50,13 +50,3 @@ Sri Athithya Kruth, [19.10.21 21:14] dollarbot, [19.10.21 21:14] The following expenditure has been recorded: You have spent $1212.0 for Food on 19-Oct-2021 21:14 - -Sri Athithya Kruth, [19.10.21 21:14] -/history - -dollarbot, [19.10.21 21:14] -Here is your spending history : -DATE, CATEGORY, AMOUNT ----------------------- -19-Oct-2021 21:13,Food,10.0 -19-Oct-2021 21:14,Food,1212.0 \ No newline at end of file From 25a29c887452a93e43c7820ed4020352306ba842 Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 19 Oct 2021 21:52:11 -0400 Subject: [PATCH 08/56] Created add.md - readme for delete.py feature --- docs/delete.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/delete.md diff --git a/docs/delete.md b/docs/delete.md new file mode 100644 index 000000000..1eec2da7b --- /dev/null +++ b/docs/delete.md @@ -0,0 +1,25 @@ +# About MyDollarBot's /delete Feature +This feature enables the user to delete all of their saved records till date in their expense tracker. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/delete.py) + +# Code Description +## Functions + +1. run(message, bot): +This is the main function used to implement the delete feature. It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the main code.py function. It calls helper to get the user history i.e chat ids of all user in the application, and if the user requesting a delete has their data saved in myDollarBot i.e their chat ID has been logged before, run calls the deleteHistory(chat_id): to remove it. Then it ensures this removal is saved in the datastore. + +2. deleteHistory(chat_id): +It takes 1 argument for processing - **chat_id** which is the chat_id of the user whose data is to deleted from the user list. It removes this entry from the user list. + +# How to run this feature? +Once the project is running(please follow the instructions given in the main README.md for this), please type /add into the telegram bot. + +Below you can see an example in text format: + +Sri Athithya Kruth, [19.10.21 21:50] +/delete + +dollarbot,[] +History has been deleted! \ No newline at end of file From 2f129ddeb62361a1e5341c17acd3ac707ba8e19b Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 19 Oct 2021 22:04:53 -0400 Subject: [PATCH 09/56] fix: delete.py now works correctly --- code/delete.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/delete.py b/code/delete.py index a1041a61f..355689a3d 100644 --- a/code/delete.py +++ b/code/delete.py @@ -4,9 +4,8 @@ def run(message, bot): global user_list chat_id = message.chat.id - helper.read_json() delete_history_text = "" - user_list = helper.getUserHistory() + user_list = helper.read_json() if (str(chat_id) in user_list): helper.write_json(deleteHistory(chat_id)) delete_history_text = "History has been deleted!" From 44e0b08b21a1f9e80f170990ef633ac7577d4888 Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 19 Oct 2021 22:20:50 -0400 Subject: [PATCH 10/56] docs: added code.md --- docs/code.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/code.md diff --git a/docs/code.md b/docs/code.md new file mode 100644 index 000000000..d312e5723 --- /dev/null +++ b/docs/code.md @@ -0,0 +1,35 @@ +# About MyDollarBot's code.py file +code.py is the main file from where calls to the corresponding .py files for all features are sent. It contains a number of endpoints which redirect to function calls in the corresponding files. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/code.py) + +# Code Description +## Functions + +1. main() +The entire bot's execution begins here. It ensure the **bot** variable begins polling and actively listening for requests from telegram. + +2. listener(user_requests): +Takes 1 argument **user_requests** and logs all user interaction with the bot including all bot commands run and any other issue logs. + +3. start_and_menu_command(m): +Prints out the the main menu displaying the features that the bot offers and the corresponding commands to be run from the Telegram UI to use these features. Commands used to run this: commands=['start', 'menu'] + +4. command_add(message) +Takes 1 argument **message** which contains the message from the user along with the chat ID of the user chat. It then calls add.py to run to execute the add functionality. Commands used to run this: commands=['add'] + +5. command_history(message): +Takes 1 argument **message** which contains the message from the user along with the chat ID of the user chat. It then calls history.py to run to execute the add functionality. Commands used to run this: commands=['history'] + +6. command_edit(message): +Takes 1 argument **message** which contains the message from the user along with the chat ID of the user chat. It then calls edit.py to run to execute the add functionality. Commands used to run this: commands=['edit'] + +7. command_display(message): +Takes 1 argument **message** which contains the message from the user along with the chat ID of the user chat. It then calls display.py to run to execute the add functionality. Commands used to run this: commands=['display'] + +8. command_delete(message): +Takes 1 argument **message** which contains the message from the user along with the chat ID of the user chat. It then calls delete.py to run to execute the add functionality. Commands used to run this: commands=['display'] + +# How to run this feature? +This file contains information on the main code.py file from where all features are run. Instructions to run this are the same as instructions to run the project and can be found in README.md. \ No newline at end of file From 9590c7066cd9866176c948836a986d3a319a2795 Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Wed, 20 Oct 2021 11:55:40 -0400 Subject: [PATCH 11/56] feat: Simplify installation --- code/code.py | 9 ++++++--- requirements.txt | 2 +- run.sh | 28 ++++++++++++++++++++++++++++ user.properties | 0 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 run.sh create mode 100644 user.properties diff --git a/code/code.py b/code/code.py index f3c119c93..4e99ba679 100644 --- a/code/code.py +++ b/code/code.py @@ -10,11 +10,14 @@ import delete import add from datetime import datetime +from jproperties import Properties -api_token = "2058952091:AAGVtSVBKT1AnjTpNyojdNz4sgD68pY3mzM" +configs = Properties() -# global variables to store user choice, user list, spend categories, etc -user_list = {} +with open('user.properties', 'rb') as read_prop: + configs.load(read_prop) + +api_token = str(configs.get('api_token').data) bot = telebot.TeleBot(api_token) diff --git a/requirements.txt b/requirements.txt index fdc941b0e..905caef49 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ pyTelegramBotAPI==4.1.0 pytest==6.2.4 - +jproperties diff --git a/run.sh b/run.sh new file mode 100644 index 000000000..680d05319 --- /dev/null +++ b/run.sh @@ -0,0 +1,28 @@ +pip install -r requirements.txt + +api_token=$(grep "api_token" user.properties|cut -d'=' -f2) + +if [ -z "$api_token" ] +then + echo "Api token missing: Execute the following steps to generate Api token" + echo + echo "1. Download and install the Telegram desktop application for your system from the following site: https://desktop.telegram.org/" + echo "2. Once you login to your Telegram account, search for \"BotFather\" in Telegram. Click on \"Start\" --> enter the following command:" + echo "/newbot" + echo "3. Follow the instructions on screen and choose a name for your bot. Post this, select a username for your bot that ends with \"bot\" (as per the instructions on your Telegram screen)" + echo "4. BotFather will now confirm the creation of your bot and provide a TOKEN to access the HTTP API - copy this token." + echo + echo "Add Api token and continue?(y/n)" + read option + if [ $option == 'y' -o $option == 'Y' ] + then + echo "Enter the copied token: " + read api_token + echo "api_token="$api_token >> user.properties + fi +fi + +if [ -n "$api_token" ] +then + python3 code/code.py +fi diff --git a/user.properties b/user.properties new file mode 100644 index 000000000..e69de29bb From 6904af62a1d232bf6acb7e202df5d3ed2aa78cc2 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 20:26:29 -0400 Subject: [PATCH 12/56] fixed indendation and added style checks --- .travis.yml | 1 + run.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 86d353044..54821b1a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,6 @@ install: - pip install . - pip install -r requirements.txt script: + - flake8 --ignore=E501,W605 - pytest test/ diff --git a/run.sh b/run.sh index 680d05319..3691de932 100644 --- a/run.sh +++ b/run.sh @@ -1,4 +1,4 @@ -pip install -r requirements.txt +pip3 install -r requirements.txt api_token=$(grep "api_token" user.properties|cut -d'=' -f2) From e105a5289aff942fbb45bdc4c9f95fba55696e84 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 20:29:46 -0400 Subject: [PATCH 13/56] Update run.sh fixed indendation and added style checks --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 3691de932..680d05319 100644 --- a/run.sh +++ b/run.sh @@ -1,4 +1,4 @@ -pip3 install -r requirements.txt +pip install -r requirements.txt api_token=$(grep "api_token" user.properties|cut -d'=' -f2) From 6763972a193aa484f5b2cc08c8b19380ec0c85ec Mon Sep 17 00:00:00 2001 From: Athithya Date: Wed, 20 Oct 2021 20:34:26 -0400 Subject: [PATCH 14/56] added display.md docs --- docs/display.md | 40 ++++++++++++++++++++++++++++++++++++++++ user.properties | 1 + 2 files changed, 41 insertions(+) create mode 100644 docs/display.md diff --git a/docs/display.md b/docs/display.md new file mode 100644 index 000000000..7b4cec1ab --- /dev/null +++ b/docs/display.md @@ -0,0 +1,40 @@ +# About MyDollarBot's /display Feature +This feature enables the user to view their expenses for the past month or past day. The option to choose month or day pops up on the screen and they can choose their preference to be displayed afterwards. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/display.py) + +# Code Description +## Functions + +1. run(message, bot): +This is the main function used to implement the delete feature. It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the main code.py function. + +It gets the options for the display period from the helper.py file's getSpendDisplayOptions() method and then makes the Telegram bot display them for the user to choose along with a message indicating this. It then passes control to the display_total() function for further processing. + +2. display_total(message, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the run(message, bot): function in the same file. This function loads the user's data using the helper file's getUserHistory(chat_id) method. After this, depending on the option user has chosen on the UI, it calls the calculate_spendings(queryResult): to process the queried data to return to the user after which it finally passes the data to the UI for the user to view. + +3. calculate_spendings(queryResult): +Takes 1 argument for processing - **queryResult** which is the query result from the display total function in the same file. It parses the query result and turns it into a form suitable for display on the UI by the user. + +# How to run this feature? +Sri Athithya Kruth, [20.10.21 20:33] +/display + +mydollarbot20102021, [20.10.21 20:33] +[In reply to Sri Athithya Kruth] +Please select a category to see the total expense + +Sri Athithya Kruth, [20.10.21 20:33] +Day + +mydollarbot20102021, [20.10.21 20:33] +Hold on! Calculating... + +mydollarbot20102021, [20.10.21 20:33] +Here are your total spendings day: +CATEGORIES,AMOUNT +---------------------- +Transport $1022.0 +Groceries $12.0 \ No newline at end of file diff --git a/user.properties b/user.properties index e69de29bb..f08ac3a5e 100644 --- a/user.properties +++ b/user.properties @@ -0,0 +1 @@ +api_token=2066526595:AAFzp8ePg8Upce_pCpKw0Qryhqwom1EMi2c From 2927dcf97ce54957f969236524d1ba1438e9ee53 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 20:45:26 -0400 Subject: [PATCH 15/56] Update requirements.txt Updated flake8 package --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 905caef49..ec4f4c434 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ pyTelegramBotAPI==4.1.0 pytest==6.2.4 jproperties +flake8 From a24df24b75cda9f0cd6935ae4085f895b94c8348 Mon Sep 17 00:00:00 2001 From: Athithya Date: Wed, 20 Oct 2021 20:50:55 -0400 Subject: [PATCH 16/56] added docs: edit.md --- docs/edit.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/edit.md diff --git a/docs/edit.md b/docs/edit.md new file mode 100644 index 000000000..ddf5a8d4c --- /dev/null +++ b/docs/edit.md @@ -0,0 +1,33 @@ +# About MyDollarBot's /edit Feature +This feature enables the user to edit a previously entered expense in the app. The use can change the amount set in the bot with this command. + +Please note that this is still a Work In Progress. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/edit.py) + +# Code Description +## Functions + +1. run(message, bot): +This is the main function used to implement the delete feature. It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the main code.py function. It gets the details for the expense to be edited from here and passes control onto edit2(m, bot): for further processing. + +2. edit2(message, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the run(message, bot): function in the same file. It validates the date provided by the user to see if it's been correctly entered. If not, it throws an error stating the date is incorrect. If the date is correct, it then asks the user what they would like to edit for the expense in question, passing on to def edit3(m, bot): for further processing. + +3. def edit3(message, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit2(m, bot):: function in the same file. Based on the category chosen for editing by the user, it redirects to the corresponding function for further processing. + +4. def edit_date(m, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of date change. + +5. def edit_cost(m, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of cost change. + +6. def edit_cat(m, bot): +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of category change. + +# How to run this feature? +Sri Athithya Kruth, [20.10.21 20:33] +/edit +(WORK IN PROGRESS) \ No newline at end of file From 938da5adbdcf427762001a61fd0457ece632a8b3 Mon Sep 17 00:00:00 2001 From: Athithya Date: Wed, 20 Oct 2021 20:54:16 -0400 Subject: [PATCH 17/56] added docs: history.md --- docs/history.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 docs/history.md diff --git a/docs/history.md b/docs/history.md new file mode 100644 index 000000000..d95253b74 --- /dev/null +++ b/docs/history.md @@ -0,0 +1,35 @@ +# About MyDollarBot's /history Feature +This feature enables the user to view all of their stored records i.e it gives a historical view of all the expenses stored in MyDollarBot. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/history.py) + +# Code Description +## Functions + +1. run(message, bot): +This is the main function used to implement the delete feature. It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the main code.py function. It calls helper.py to get the user's historical data and based on whether there is data available, it either prints an error message or displays the user's historical data. + +# How to run this feature? +Once the project is running(please follow the instructions given in the main README.md for this), please type /add into the telegram bot. + +Below you can see an example in text format: + +Sri Athithya Kruth, [20.10.21 20:33] +/display + +Sri Athithya Kruth, [20.10.21 20:33] +Day + +mydollarbot20102021, [20.10.21 20:33] +Hold on! Calculating... + +Sri Athithya Kruth, [20.10.21 20:53] +/history + +mydollarbot20102021, [20.10.21 20:53] +Here is your spending history : +DATE, CATEGORY, AMOUNT +---------------------- +20-Oct-2021 20:33,Transport,1022.0 +20-Oct-2021 20:33,Groceries,12.0 \ No newline at end of file From 1d79837fd77b9429be107589f0e8fb6f57f2916a Mon Sep 17 00:00:00 2001 From: Athithya Date: Wed, 20 Oct 2021 21:01:57 -0400 Subject: [PATCH 18/56] added docs: helper.md --- docs/helper.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/helper.md diff --git a/docs/helper.md b/docs/helper.md new file mode 100644 index 000000000..9b5be25d4 --- /dev/null +++ b/docs/helper.md @@ -0,0 +1,43 @@ +# About MyDollarBot's /helper class +The helper file contains a set of functions that are commonly used for repeated tasks in the various features of MyDollarBot. Since these come up often, we have put them all up here in a separate file for reusability. + +# Location of Code for this Feature +The code that implements this feature can be found [here](https://github.com/sak007/MyDollarBot/blob/backlogs/code/helper.py) + +# Code Description +## Functions + +1. read_json(): +Function to load .json expense record data + +2. write_json(user_list): +Stores data into the datastore of the bot. + +3. validate_entered_amount(amount_entered): +Takes 1 argument, **amount_entered**. It validates this amount's format to see if it has been correctly entered by the user. + +4. getUserHistory(chat_id): +Takes 1 argument **chat_id** and uses this to get the relevant user's historical data. + +5. getSpendCategories(): +This functions returns the spend categories used in the bot. These are defined the same file. + +6. getSpendDisplayOptions(): +This functions returns the spend display options used in the bot. These are defined the same file. + +7. getCommands(): +This functions returns the command options used in the bot. These are defined the same file. + +8. def getDateFormat(): +This functions returns the date format used in the bot. + +9. def getTimeFormat(): +This functions returns the time format used in the bot. + +10. def getMonthFormat(): +This functions returns the month format used in the bot. + +# How to run this feature? +Once the project is running(please follow the instructions given in the main README.md for this), please type /add into the telegram bot. + +This file is not a feature and cannot be run per se. Its functions are used all over by the other files as it provides helper functions for various functionalities and features. \ No newline at end of file From 17087abab8b985bbc97528785ed390d6d3a1f86d Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 21:53:44 -0400 Subject: [PATCH 19/56] Updated travis.yml with codecoverage --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 86d353044..a22955906 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,3 +8,5 @@ install: script: - pytest test/ +after_success: + - bash <(curl -s https://codecov.io/bash) -t c18f2a5b-6240-4bec-a551-b427163f05b8 From ed61930100279fc9e6b849ed1c6e0553db1c5883 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 21:54:06 -0400 Subject: [PATCH 20/56] Update .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a22955906..62cad3c0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,5 @@ install: - pip install -r requirements.txt script: - pytest test/ - after_success: - bash <(curl -s https://codecov.io/bash) -t c18f2a5b-6240-4bec-a551-b427163f05b8 From 4d2f3b26de5c8eb6d8c062ee36874dd2be71d398 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 22:07:42 -0400 Subject: [PATCH 21/56] Added CodeCov --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 54821b1a0..0e0998dbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,5 @@ install: script: - flake8 --ignore=E501,W605 - pytest test/ - +after_success: + - bash <(curl -s https://codecov.io/bash) -t c18f2a5b-6240-4bec-a551-b427163f05b8 From b0baea375ef7158a6ba1b3ba9ce61fdd41993d27 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Wed, 20 Oct 2021 22:17:39 -0400 Subject: [PATCH 22/56] updated travis.yml and requirements for codecov --- .travis.yml | 4 +++- requirements.txt | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e0998dbc..c94ff03f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,10 @@ python: install: - pip install . - pip install -r requirements.txt + - pip install coverage + - pip install codecov script: - flake8 --ignore=E501,W605 - - pytest test/ + - coverage run -m pytest -q test/ after_success: - bash <(curl -s https://codecov.io/bash) -t c18f2a5b-6240-4bec-a551-b427163f05b8 diff --git a/requirements.txt b/requirements.txt index ec4f4c434..319511ff2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ pyTelegramBotAPI==4.1.0 pytest==6.2.4 jproperties -flake8 +flake8==4.0.1 +coverage==6.0.2 From aef8facda0af7ab68d756e2a0ff78f35711324c3 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Fri, 22 Oct 2021 10:43:59 -0400 Subject: [PATCH 23/56] Edit functionality working now --- code/edit.py | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/code/edit.py b/code/edit.py index 23c034c3d..6ebbf63ac 100644 --- a/code/edit.py +++ b/code/edit.py @@ -4,13 +4,12 @@ def run(m, bot): - helper.read_json() - global user_list + user_list = helper.read_json() chat_id = m.chat.id - if (str(chat_id) in user_list): + if str(chat_id) in user_list: info = bot.reply_to(m, "Please enter the date and category of the transaction you made (Eg: 01-Mar-2021,Transport)") - bot.register_next_step_handler(info, edit2, bot) + bot.register_next_step_handler(info, edit2, bot, user_list) else: bot.reply_to(chat_id, "No data found") @@ -18,16 +17,18 @@ def run(m, bot): i_edit = -1 -def edit2(m, bot): +def edit2(m, bot, user_list): + print("Inside edit 2") global i_edit i_edit = -1 chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) info = m.text + print("data_edit:"+str(data_edit)) date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" info = info.split(',') x = re.search(date_format, info[0]) - if(x is None): + if x is None: bot.reply_to(m, "The date is incorrect") return @@ -36,44 +37,47 @@ def edit2(m, bot): choices = ['Date', 'Category', 'Cost'] for c in choices: markup.add(c) - + print("Outside record:") for record in data_edit: i_edit = i_edit + 1 record = record.split(',') - if info[0] == record[0][0:11] and info[1] == record[1]: + + print("info[1]:"+str(info[1])+", record[1]:"+str(record[1])) + if info[0] == record[0][0:11] and str(info[1]).strip() == str(record[1]).strip(): + print("Inside what do u want to update") choice = bot.reply_to(m, "What do you want to update?", reply_markup=markup) - bot.register_next_step_handler(choice, edit3) + bot.register_next_step_handler(choice, edit3, bot, user_list) break -def edit3(m, bot): +def edit3(m, bot, user_list): choice1 = m.text markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 for cat in helper.getSpendCategories(): markup.add(cat) - if(choice1 == 'Date'): + if choice1 == 'Date': new_date = bot.reply_to(m, "Please enter the new date (in dd-mmm-yyy format)") - bot.register_next_step_handler(new_date, edit_date) + bot.register_next_step_handler(new_date, edit_date, bot, user_list) - if(choice1 == 'Category'): + if choice1 == 'Category': new_cat = bot.reply_to(m, "Please select the new category", reply_markup=markup) - bot.register_next_step_handler(new_cat, edit_cat) + bot.register_next_step_handler(new_cat, edit_cat, bot, user_list) - if(choice1 == 'Cost'): + if choice1 == 'Cost': new_cost = bot.reply_to(m, "Please type the new cost") - bot.register_next_step_handler(new_cost, edit_cost) + bot.register_next_step_handler(new_cost, edit_cost, bot, user_list) -def edit_date(m, bot): +def edit_date(m, bot, user_list): global i_edit new_date = m.text date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) x1 = re.search(date_format, new_date) - if(x1 is None): + if x1 is None: bot.reply_to(m, "The date is incorrect") return record = data_edit[i_edit].split(',') @@ -84,7 +88,7 @@ def edit_date(m, bot): bot.reply_to(m, "Date is updated") -def edit_cat(m, bot): +def edit_cat(m, bot, user_list): global i_edit chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) @@ -97,13 +101,13 @@ def edit_cat(m, bot): bot.reply_to(m, "Category is updated") -def edit_cost(m, bot): +def edit_cost(m, bot, user_list): global i_edit new_cost = m.text chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) - if(helper.validate_entered_amount(new_cost) != 0): + if helper.validate_entered_amount(new_cost) != 0: record = data_edit[i_edit].split(',') record[2] = new_cost data_edit[i_edit] = record[0] + ',' + record[1] + ',' + str(float(record[2])) From 40b5072a4ef9586893a066c6fd087399e0bb2400 Mon Sep 17 00:00:00 2001 From: rjain09 <72677919+rjain09@users.noreply.github.com> Date: Sat, 23 Oct 2021 11:10:31 -0400 Subject: [PATCH 24/56] Updated the badges --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 74aeb3048..068fd8b5a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5542548.svg)](https://doi.org/10.5281/zenodo.5542548) [![Platform](https://img.shields.io/badge/Platform-Telegram-blue)](https://desktop.telegram.org/) [![Build Status](https://app.travis-ci.com/deekay2310/MyDollarBot.svg?branch=main)](https://app.travis-ci.com/github/deekay2310/MyDollarBot) +[![codecov](https://codecov.io/gh/sak007/MyDollarBot/branch/main/graph/badge.svg?token=5AYMR8MNMP)](https://codecov.io/gh/sak007/MyDollarBot) +[![GitHub issues](https://img.shields.io/github/issues/sak007/MyDollarBot)](https://github.com/sak007/MyDollarBot/issues?q=is%3Aopen+is%3Aissue) +[![GitHub closed issues](https://img.shields.io/github/issues-closed/sak007/MyDollarBot)](https://github.com/sak007/MyDollarBot/issues?q=is%3Aissue+is%3Aclosed) +![Lines of code](https://img.shields.io/tokei/lines/github/sak007/MyDollarBot)
From 6941898e646b21f7cd47476a20f407a8d6911e32 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sat, 23 Oct 2021 11:22:51 -0400 Subject: [PATCH 25/56] Edit functionality - build issue fix --- code/edit.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/edit.py b/code/edit.py index 6ebbf63ac..c3b0fb2bd 100644 --- a/code/edit.py +++ b/code/edit.py @@ -24,7 +24,6 @@ def edit2(m, bot, user_list): chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) info = m.text - print("data_edit:"+str(data_edit)) date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" info = info.split(',') x = re.search(date_format, info[0]) @@ -41,8 +40,6 @@ def edit2(m, bot, user_list): for record in data_edit: i_edit = i_edit + 1 record = record.split(',') - - print("info[1]:"+str(info[1])+", record[1]:"+str(record[1])) if info[0] == record[0][0:11] and str(info[1]).strip() == str(record[1]).strip(): print("Inside what do u want to update") choice = bot.reply_to(m, "What do you want to update?", reply_markup=markup) From 6a324e72df35a201aa3fac4bc86d20987a845654 Mon Sep 17 00:00:00 2001 From: Sri Athithya Kruth Babu Date: Wed, 27 Oct 2021 09:24:14 +0530 Subject: [PATCH 26/56] Updated with more info --- docs/edit.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/edit.md b/docs/edit.md index ddf5a8d4c..c1dc8116a 100644 --- a/docs/edit.md +++ b/docs/edit.md @@ -19,15 +19,15 @@ It takes 2 arguments for processing - **message** which is the message from the It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit2(m, bot):: function in the same file. Based on the category chosen for editing by the user, it redirects to the corresponding function for further processing. 4. def edit_date(m, bot): -It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of date change. +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of date change and edits. 5. def edit_cost(m, bot): -It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of cost change. +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of cost change and edits. 6. def edit_cat(m, bot): -It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of category change. +It takes 2 arguments for processing - **message** which is the message from the user, and **bot** which is the telegram bot object from the edit3(m, bot):: function in the same file. It takes care of category change and edits. # How to run this feature? Sri Athithya Kruth, [20.10.21 20:33] /edit -(WORK IN PROGRESS) \ No newline at end of file +(WORK IN PROGRESS) From cfa385f3d0211e299d9d490148ff202ea271e05f Mon Sep 17 00:00:00 2001 From: Sri Athithya Kruth Babu Date: Wed, 27 Oct 2021 09:28:10 +0530 Subject: [PATCH 27/56] Corrected display issues --- docs/display.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/display.md b/docs/display.md index 7b4cec1ab..5a0711e98 100644 --- a/docs/display.md +++ b/docs/display.md @@ -33,8 +33,10 @@ mydollarbot20102021, [20.10.21 20:33] Hold on! Calculating... mydollarbot20102021, [20.10.21 20:33] + Here are your total spendings day: + CATEGORIES,AMOUNT ---------------------- Transport $1022.0 -Groceries $12.0 \ No newline at end of file +Groceries $12.0 From 4e25b947ca51d2dea1406ad40d541b09669507b7 Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Thu, 28 Oct 2021 20:15:08 -0400 Subject: [PATCH 28/56] test: testcases for helper.py --- code/__init__.py | 7 -- test/test_helper.py | 206 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 test/test_helper.py diff --git a/code/__init__.py b/code/__init__.py index 63fa0f3e9..e69de29bb 100644 --- a/code/__init__.py +++ b/code/__init__.py @@ -1,7 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Wed Sep 29 17:10:59 2021 - -@author: deekay -""" diff --git a/test/test_helper.py b/test/test_helper.py new file mode 100644 index 000000000..e63412fb6 --- /dev/null +++ b/test/test_helper.py @@ -0,0 +1,206 @@ +from code import helper +import pytest + +MOCK_CHAT_ID = 101 +MOCK_USER_DATA = { + str(MOCK_CHAT_ID): ["correct_mock_value"], + '102': ["wrong_mock_value"] +} + + +@pytest.mark.skipif(True, reason="Add none check") +def test_validate_entered_amount_none(): + result = helper.validate_entered_amount(None) + if result: + assert False, 'None is not a valid amount' + else: + assert True + + +def test_validate_entered_amount_int(): + val = '101' + result = helper.validate_entered_amount(val) + if result: + assert True + else: + assert False, val + ' is valid amount' + + +def test_validate_entered_amount_int_max(): + val = '999999999999999' + result = helper.validate_entered_amount(val) + if result: + assert True + else: + assert False, val + ' is valid amount' + + +def test_validate_entered_amount_int_outofbound(): + val = '9999999999999999' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount(out of bound)' + else: + assert True + + +def test_validate_entered_amount_float(): + val = '101.11' + result = helper.validate_entered_amount(val) + if result: + assert True + else: + assert False, val + ' is valid amount' + + +@pytest.mark.skipif(True, reason="float value < 10^14 is valid. update the checker") +def test_validate_entered_amount_float_max(): + val = '999999999999999.9999' + result = helper.validate_entered_amount(val) + if result: + assert True + else: + assert False, val + ' is valid amount' + + +@pytest.mark.skipif(True, reason="float value < 10^14 is valid. update the checker") +def test_validate_entered_amount_float_more_decimal(): + val = '9999999999.999999999' + result = helper.validate_entered_amount(val) + if result: + assert True + else: + assert False, val + ' is valid amount' + + +def test_validate_entered_amount_float_outofbound(): + val = '9999999999999999.99' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount(out of bound)' + else: + assert True + + +def test_validate_entered_amount_string(): + val = 'agagahaaaa' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount' + else: + assert True + + +def test_validate_entered_amount_string_with_dot(): + val = 'agaga.aaa' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount' + else: + assert True + + +def test_validate_entered_amount_special_char(): + val = '$%@*@.@*' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount' + else: + assert True + + +def test_validate_entered_amount_alpha_num(): + val = '22e62a' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount' + else: + assert True + + +def test_validate_entered_amount_mixed(): + val = 'a14&^%.hs827' + result = helper.validate_entered_amount(val) + if result: + assert False, val + ' is not a valid amount' + else: + assert True + + +def test_getUserHistory_without_data(mocker): + mocker.patch.object(helper, 'read_json') + helper.read_json.return_value = {} + result = helper.getUserHistory(MOCK_CHAT_ID) + if result is None: + assert True + else: + assert False, 'Result is not None when user data does not exist' + + +def test_getUserHistory_with_data(mocker): + mocker.patch.object(helper, 'read_json') + helper.read_json.return_value = MOCK_USER_DATA + result = helper.getUserHistory(MOCK_CHAT_ID) + if result == MOCK_USER_DATA[str(MOCK_CHAT_ID)]: + assert True + else: + assert False, 'User data is available but not found' + + +@pytest.mark.skipif(True, reason="None check should be added for user_data") +def test_getUserHistory_with_none(mocker): + mocker.patch.object(helper, 'read_json') + helper.read_json.return_value = None + result = helper.getUserHistory(MOCK_CHAT_ID) + if result is None: + assert True + else: + assert False, 'Result is not None when the file does not exist' + + +def test_getSpendCategories(): + result = helper.getSpendCategories() + if result == helper.spend_categories: + assert True + else: + assert False, 'expected spend categories are not returned' + + +def test_getSpendDisplayOptions(): + result = helper.getSpendDisplayOptions() + if result == helper.spend_display_option: + assert True + else: + assert False, 'expected spend display options are not returned' + + +def test_getCommands(): + result = helper.getCommands() + if result == helper.commands: + assert True + else: + assert False, 'expected commands are not returned' + + +def test_getDateFormat(): + result = helper.getDateFormat() + if result == helper.dateFormat: + assert True + else: + assert False, 'expected date format are not returned' + + +def test_getTimeFormat(): + result = helper.getTimeFormat() + if result == helper.timeFormat: + assert True + else: + assert False, 'expected time format are not returned' + + +def test_getMonthFormat(): + result = helper.getMonthFormat() + if result == helper.monthFormat: + assert True + else: + assert False, 'expected month format are not returned' From a1859047d081c0c8b63bb9769be043982ece3b92 Mon Sep 17 00:00:00 2001 From: Ashok Kumar S Date: Thu, 28 Oct 2021 20:18:29 -0400 Subject: [PATCH 29/56] chore: add pytest-mock in requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 319511ff2..186948622 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ pytest==6.2.4 jproperties flake8==4.0.1 coverage==6.0.2 +pytest-mock From 1148f8105f33a1a0c6922481c315d281128d9281 Mon Sep 17 00:00:00 2001 From: Athithya Date: Tue, 26 Oct 2021 23:54:42 -0400 Subject: [PATCH 30/56] added test for add.py --- code/add.py | 1 + test/test_add.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/test_add.py diff --git a/code/add.py b/code/add.py index b6b6308d5..604af12ef 100644 --- a/code/add.py +++ b/code/add.py @@ -3,6 +3,7 @@ from telebot import types from datetime import datetime + option = {} diff --git a/test/test_add.py b/test/test_add.py new file mode 100644 index 000000000..0c34fe5be --- /dev/null +++ b/test/test_add.py @@ -0,0 +1,28 @@ +import sys +import os +import telebot +from telebot import types +from unittest.mock import MagicMock + +sys.path.insert(0, os.getcwd() + "/code") +from add import run + +bot = telebot.TeleBot("1") +bot.reply_to = MagicMock(return_value=True) +bot.register_next_step_handler = MagicMock(return_value=True) + + +def test_run(): + message = create_message("hello from test run!") + ret_msg = run(message, bot) + assert ret_msg is None + + +def create_message(text): + params = {'messagebody': text} + chat = types.User(11, False, 'test') + return types.Message(1, None, None, chat, 'text', params, "") + + +def test_add_user_record(): + pass From d80d064372b4d70f5fc0cc7c091fd1b7969d159b Mon Sep 17 00:00:00 2001 From: Athithya Date: Fri, 29 Oct 2021 00:42:20 -0400 Subject: [PATCH 31/56] added test_add.py test cases --- code/__init__.py | 3 ++ test/test_add.py | 83 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/code/__init__.py b/code/__init__.py index e69de29bb..a93f95320 100644 --- a/code/__init__.py +++ b/code/__init__.py @@ -0,0 +1,3 @@ +import os +import sys +sys.path.insert(0, os.getcwd() + "/code") diff --git a/test/test_add.py b/test/test_add.py index 0c34fe5be..c4c78dd5c 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -1,28 +1,77 @@ -import sys -import os -import telebot +# import os +# import sys +from mock.mock import patch from telebot import types -from unittest.mock import MagicMock +# sys.path.insert(0, os.getcwd() + "/code") +from code import add -sys.path.insert(0, os.getcwd() + "/code") -from add import run -bot = telebot.TeleBot("1") -bot.reply_to = MagicMock(return_value=True) -bot.register_next_step_handler = MagicMock(return_value=True) +@patch('telebot.telebot') +def test_run(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("hello from test run!") + add.run(message, mc) + assert(mc.reply_to.called) -def test_run(): - message = create_message("hello from test run!") - ret_msg = run(message, bot) - assert ret_msg is None +@patch('telebot.telebot') +def test_post_category_selection_working(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + + message = create_message("hello from testing!") + add.post_category_selection(message, mc) + assert(mc.send_message.called) + + +@patch('telebot.telebot') +def test_post_category_selection_noMatchingCategory(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = [] + mc.reply_to.return_value = True + + mocker.patch.object(add, 'helper') + add.helper.getSpendCategories.return_value = None + + message = create_message("hello from testing!") + add.post_category_selection(message, mc) + assert(mc.reply_to.called) + + +@patch('telebot.telebot') +def test_post_amount_input_working(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + + message = create_message("hello from testing!") + add.post_category_selection(message, mc) + assert(mc.send_message.called) + + +@patch('telebot.telebot') +def test_post_amount_input_nonworking(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + mc.reply_to.return_value = True + mocker.patch.object(add, 'helper') + add.helper.validate_entered_amount.return_value = 0 + + message = create_message("hello from testing!") + add.post_category_selection(message, mc) + assert(mc.reply_to.called) + + +def test_add_user_record(mocker): + mocker.patch.object(add, 'helper') + add.helper.read_json.return_value = {} + + addeduserrecord = add.add_user_record(1, "record : test") + print(addeduserrecord) + assert(addeduserrecord) def create_message(text): params = {'messagebody': text} chat = types.User(11, False, 'test') return types.Message(1, None, None, chat, 'text', params, "") - - -def test_add_user_record(): - pass From 2c2bd8886cc8cff3258c8023ce699dff49eef2bd Mon Sep 17 00:00:00 2001 From: Athithya Date: Fri, 29 Oct 2021 00:55:44 -0400 Subject: [PATCH 32/56] cleaned up test_add.py --- test/test_add.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_add.py b/test/test_add.py index c4c78dd5c..e8bd5870e 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -1,8 +1,5 @@ -# import os -# import sys from mock.mock import patch from telebot import types -# sys.path.insert(0, os.getcwd() + "/code") from code import add From 668268cd8c5bf686fc83b66d5012ee57d482714f Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Sat, 30 Oct 2021 18:40:49 -0400 Subject: [PATCH 33/56] Added Test Cases for Delete.py and History.py. Updated History.py with indendation fix --- code/history.py | 4 +- run.sh | 2 +- test/dummy_expense_record.json | 44 ++++++++++++++++++++++ test/test_delete.py | 68 ++++++++++++++++++++++++++++++++++ test/test_history.py | 63 +++++++++++++++++++++++++++++++ user.properties | 2 +- 6 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 test/dummy_expense_record.json create mode 100644 test/test_delete.py create mode 100644 test/test_history.py diff --git a/code/history.py b/code/history.py index 0b7215dc8..f13d33f84 100644 --- a/code/history.py +++ b/code/history.py @@ -1,3 +1,5 @@ +from mock.mock import patch +from telebot import types import helper import logging @@ -16,7 +18,7 @@ def run(message, bot): else: for rec in user_history: spend_total_str += str(rec) + "\n" - bot.send_message(chat_id, spend_total_str) + bot.send_message(chat_id, spend_total_str) except Exception as e: logging.exception(str(e)) bot.reply_to(message, "Oops!" + str(e)) diff --git a/run.sh b/run.sh index 680d05319..3691de932 100644 --- a/run.sh +++ b/run.sh @@ -1,4 +1,4 @@ -pip install -r requirements.txt +pip3 install -r requirements.txt api_token=$(grep "api_token" user.properties|cut -d'=' -f2) diff --git a/test/dummy_expense_record.json b/test/dummy_expense_record.json new file mode 100644 index 000000000..bd91f8981 --- /dev/null +++ b/test/dummy_expense_record.json @@ -0,0 +1,44 @@ +{ + "894127939": [ + "28-Oct-2021 15:27,Food,2.3", + "28-Oct-2021 15:28,Food,15.75", + "28-Oct-2021 15:28,Food,9.99", + "28-Oct-2021 15:28,Groceries,20.0", + "28-Oct-2021 15:28,Utilities,10.0", + "28-Oct-2021 15:28,Transport,7.28", + "28-Oct-2021 15:28,Transport,25.99", + "28-Oct-2021 15:31,Utilities,6.0", + "28-Oct-2021 15:38,Food,10.0", + "28-Oct-2021 15:40,Groceries,80.0" + ], + "8941298739": [ + "28-Oct-2021 15:27,Food,2.3", + "28-Oct-2021 15:28,Food,15.75", + "28-Oct-2021 15:28,Food,9.99", + "28-Oct-2021 15:28,Groceries,20.0", + "28-Oct-2021 15:28,Utilities,10.0", + "28-Oct-2021 15:28,Transport,7.28", + "28-Oct-2021 15:28,Transport,25.99", + "28-Oct-2021 15:31,Utilities,6.0", + "28-Oct-2021 15:38,Food,10.0", + "28-Oct-2021 15:40,Groceries,80.0" + ], + "1574038305": [ + + ] + , + "2614394724848": [ + "28-Oct-2021 15:27,Food,2.3", + "28-Oct-2021 15:28,Food,15.75", + "28-Oct-2021 15:28,Food,9.99", + "28-Oct-2021 15:28,Groceries,20.0", + "28-Oct-2021 15:28,Utilities,10.0", + "28-Oct-2021 15:28,Transport,7.28", + "28-Oct-2021 15:28,Transport,25.99", + "28-Oct-2021 15:31,Utilities,6.0", + "28-Oct-2021 15:38,Food,10.0", + "28-Oct-2021 15:40,Groceries,80.0" + ] +} + + diff --git a/test/test_delete.py b/test/test_delete.py new file mode 100644 index 000000000..f56558b64 --- /dev/null +++ b/test/test_delete.py @@ -0,0 +1,68 @@ +from code import delete +from code import helper +from mock import patch +from telebot import types +import os, sys, json +import pytest + + + +def test_read_json(): + os.chdir("D:\\Studies\\Masters - NCSU - Course wise\\CSC510 - Software Engg\\Project-2\\MyDollarBot\\test") + try: + if not os.path.exists('dummy_expense_record.json'): + with open('dummy_expense_record.json', 'w') as json_file: + json_file.write('{}') + return json.dumps('{}') + elif os.stat('dummy_expense_record.json').st_size != 0: + with open('dummy_expense_record.json') as expense_record: + expense_record_data = json.load(expense_record) + return expense_record_data + + except FileNotFoundError: + print("---------NO RECORDS FOUND---------") + +def create_message(text): + params = {'messagebody': text} + chat = types.User("894127939", False, 'test') + return types.Message(1, None, None, chat, 'text', params, "") + +@patch('telebot.telebot') +def test_delete_run_with_data(mock_telebot, mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(delete, 'helper') + delete.helper.read_json.return_value = MOCK_USER_DATA + delete.helper.write_json.return_value = True + MOCK_Message_data = create_message("Hello") + mc = mock_telebot.return_value + mc.send_message.return_value = True + history_check = delete.run(MOCK_Message_data, mc) + assert(delete.helper.write_json.called) + +@patch('telebot.telebot') +def test_delete_with_no_data(mock_telebot, mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(delete, 'helper') + delete.helper.read_json.return_value = {} + delete.helper.write_json.return_value = True + MOCK_Message_data = create_message("Hello") + mc = mock_telebot.return_value + mc.send_message.return_value = True + history_check = delete.run(MOCK_Message_data, mc) + assert(delete.helper.write_json.called == False) + + +# def test_run(mock_telebot, mocker): +# MOCK_USER_DATA = test_read_json() +# pre_val = len(MOCK_USER_DATA) +# chat_id = "894127939" +# test_op = delete.run(chat_id) +# post_val = len(test_op) +# +# print(pre_val) +# print(post_val) +# +# if post_val < pre_val: +# assert True +# else: +# assert False diff --git a/test/test_history.py b/test/test_history.py new file mode 100644 index 000000000..04c9d5870 --- /dev/null +++ b/test/test_history.py @@ -0,0 +1,63 @@ +from code import history +from mock.mock import patch +from telebot import types +import os, sys +import json +import pytest + +def test_read_json(): + os.chdir("D:\\Studies\\Masters - NCSU - Course wise\\CSC510 - Software Engg\\Project-2\\MyDollarBot\\test") + try: + if not os.path.exists('dummy_expense_record.json'): + with open('dummy_expense_record.json', 'w') as json_file: + json_file.write('{}') + return json.dumps('{}') + elif os.stat('dummy_expense_record.json').st_size != 0: + with open('dummy_expense_record.json') as expense_record: + expense_record_data = json.load(expense_record) + return expense_record_data + + except FileNotFoundError: + print("---------NO RECORDS FOUND---------") + +def create_message(text): + params = {'messagebody': text} + chat = types.User("2614394724848", False, 'test') + return types.Message(1, None, None, chat, 'text', params, "") + +@patch('telebot.telebot') +def test_run_with_data(mock_telebot, mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(history, 'helper') + history.helper.getUserHistory.return_value = MOCK_USER_DATA["2614394724848"] + MOCK_Message_data = create_message("Hello") + mc = mock_telebot.return_value + mc.send_message.return_value = True + history_check = history.run(MOCK_Message_data, mc) + + assert(mc.send_message.called) + +@patch('telebot.telebot') +def test_run_without_data(mock_telebot, mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(history, 'helper') + history.helper.getUserHistory.return_value = MOCK_USER_DATA["1574038305"] + MOCK_Message_data = create_message("Hello") + mc = mock_telebot.return_value + mc.send_message.return_value = True + history_check = history.run(MOCK_Message_data, mc) + + assert(mc.send_message.called) + +@patch('telebot.telebot') +def test_run_with_None(mock_telebot, mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(history, 'helper') + history.helper.getUserHistory.return_value = None + print("Is it None?", history.helper.getUserHistory.return_value) + MOCK_Message_data = create_message("Hello") + mc = mock_telebot.return_value + mc.reply_to.return_value = True + history_check = history.run(MOCK_Message_data, mc) + + assert(mc.reply_to.called) diff --git a/user.properties b/user.properties index f08ac3a5e..8b1378917 100644 --- a/user.properties +++ b/user.properties @@ -1 +1 @@ -api_token=2066526595:AAFzp8ePg8Upce_pCpKw0Qryhqwom1EMi2c + From e957aeca0231c15cbfe4dfdd7fe3e948f3ea53e7 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Sat, 30 Oct 2021 18:51:34 -0400 Subject: [PATCH 34/56] Updated Styling issues wrt flake8 - Issue #15 --- code/history.py | 2 -- test/test_delete.py | 33 +++++++++------------------------ test/test_history.py | 20 ++++++++++---------- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/code/history.py b/code/history.py index f13d33f84..49c0f657f 100644 --- a/code/history.py +++ b/code/history.py @@ -1,5 +1,3 @@ -from mock.mock import patch -from telebot import types import helper import logging diff --git a/test/test_delete.py b/test/test_delete.py index f56558b64..acf9945c0 100644 --- a/test/test_delete.py +++ b/test/test_delete.py @@ -1,10 +1,8 @@ +import os +import json from code import delete -from code import helper from mock import patch from telebot import types -import os, sys, json -import pytest - def test_read_json(): @@ -22,11 +20,13 @@ def test_read_json(): except FileNotFoundError: print("---------NO RECORDS FOUND---------") + def create_message(text): params = {'messagebody': text} chat = types.User("894127939", False, 'test') return types.Message(1, None, None, chat, 'text', params, "") + @patch('telebot.telebot') def test_delete_run_with_data(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() @@ -36,33 +36,18 @@ def test_delete_run_with_data(mock_telebot, mocker): MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value mc.send_message.return_value = True - history_check = delete.run(MOCK_Message_data, mc) + delete.run(MOCK_Message_data, mc) assert(delete.helper.write_json.called) + @patch('telebot.telebot') def test_delete_with_no_data(mock_telebot, mocker): - MOCK_USER_DATA = test_read_json() mocker.patch.object(delete, 'helper') delete.helper.read_json.return_value = {} delete.helper.write_json.return_value = True MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value mc.send_message.return_value = True - history_check = delete.run(MOCK_Message_data, mc) - assert(delete.helper.write_json.called == False) - - -# def test_run(mock_telebot, mocker): -# MOCK_USER_DATA = test_read_json() -# pre_val = len(MOCK_USER_DATA) -# chat_id = "894127939" -# test_op = delete.run(chat_id) -# post_val = len(test_op) -# -# print(pre_val) -# print(post_val) -# -# if post_val < pre_val: -# assert True -# else: -# assert False + delete.run(MOCK_Message_data, mc) + if delete.helper.write_json.called is False: + assert True diff --git a/test/test_history.py b/test/test_history.py index 04c9d5870..2b0d62f72 100644 --- a/test/test_history.py +++ b/test/test_history.py @@ -1,9 +1,9 @@ +import os +import json from code import history from mock.mock import patch from telebot import types -import os, sys -import json -import pytest + def test_read_json(): os.chdir("D:\\Studies\\Masters - NCSU - Course wise\\CSC510 - Software Engg\\Project-2\\MyDollarBot\\test") @@ -20,11 +20,13 @@ def test_read_json(): except FileNotFoundError: print("---------NO RECORDS FOUND---------") + def create_message(text): params = {'messagebody': text} chat = types.User("2614394724848", False, 'test') return types.Message(1, None, None, chat, 'text', params, "") + @patch('telebot.telebot') def test_run_with_data(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() @@ -33,10 +35,10 @@ def test_run_with_data(mock_telebot, mocker): MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value mc.send_message.return_value = True - history_check = history.run(MOCK_Message_data, mc) - + history.run(MOCK_Message_data, mc) assert(mc.send_message.called) + @patch('telebot.telebot') def test_run_without_data(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() @@ -45,19 +47,17 @@ def test_run_without_data(mock_telebot, mocker): MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value mc.send_message.return_value = True - history_check = history.run(MOCK_Message_data, mc) - + history.run(MOCK_Message_data, mc) assert(mc.send_message.called) + @patch('telebot.telebot') def test_run_with_None(mock_telebot, mocker): - MOCK_USER_DATA = test_read_json() mocker.patch.object(history, 'helper') history.helper.getUserHistory.return_value = None print("Is it None?", history.helper.getUserHistory.return_value) MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value mc.reply_to.return_value = True - history_check = history.run(MOCK_Message_data, mc) - + history.run(MOCK_Message_data, mc) assert(mc.reply_to.called) From 014632a86a173acadb9f623fa853d2d86734d646 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Sat, 30 Oct 2021 19:25:35 -0400 Subject: [PATCH 35/56] Updated Local Pth Issue. Fixed Issue #15 --- test/test_delete.py | 10 +++++----- test/test_history.py | 9 ++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/test/test_delete.py b/test/test_delete.py index acf9945c0..c5a8440ee 100644 --- a/test/test_delete.py +++ b/test/test_delete.py @@ -6,14 +6,13 @@ def test_read_json(): - os.chdir("D:\\Studies\\Masters - NCSU - Course wise\\CSC510 - Software Engg\\Project-2\\MyDollarBot\\test") try: - if not os.path.exists('dummy_expense_record.json'): - with open('dummy_expense_record.json', 'w') as json_file: + if not os.path.exists('./test/dummy_expense_record.json'): + with open('./test/dummy_expense_record.json', 'w') as json_file: json_file.write('{}') return json.dumps('{}') - elif os.stat('dummy_expense_record.json').st_size != 0: - with open('dummy_expense_record.json') as expense_record: + elif os.stat('./test/dummy_expense_record.json').st_size != 0: + with open('./test/dummy_expense_record.json') as expense_record: expense_record_data = json.load(expense_record) return expense_record_data @@ -32,6 +31,7 @@ def test_delete_run_with_data(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(delete, 'helper') delete.helper.read_json.return_value = MOCK_USER_DATA + print("Hello",MOCK_USER_DATA) delete.helper.write_json.return_value = True MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value diff --git a/test/test_history.py b/test/test_history.py index 2b0d62f72..ca8b23510 100644 --- a/test/test_history.py +++ b/test/test_history.py @@ -6,14 +6,13 @@ def test_read_json(): - os.chdir("D:\\Studies\\Masters - NCSU - Course wise\\CSC510 - Software Engg\\Project-2\\MyDollarBot\\test") try: - if not os.path.exists('dummy_expense_record.json'): - with open('dummy_expense_record.json', 'w') as json_file: + if not os.path.exists('./test/dummy_expense_record.json'): + with open('./test/dummy_expense_record.json', 'w') as json_file: json_file.write('{}') return json.dumps('{}') - elif os.stat('dummy_expense_record.json').st_size != 0: - with open('dummy_expense_record.json') as expense_record: + elif os.stat('./test/dummy_expense_record.json').st_size != 0: + with open('./test/dummy_expense_record.json') as expense_record: expense_record_data = json.load(expense_record) return expense_record_data From 134544d20b15bc493ee7d5703259fce1d3bf7e18 Mon Sep 17 00:00:00 2001 From: Subramanian Venkataraman Date: Sat, 30 Oct 2021 19:28:36 -0400 Subject: [PATCH 36/56] Fixed E231 Styling Issue in #15 --- test/test_delete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_delete.py b/test/test_delete.py index c5a8440ee..f31fc659d 100644 --- a/test/test_delete.py +++ b/test/test_delete.py @@ -31,7 +31,7 @@ def test_delete_run_with_data(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(delete, 'helper') delete.helper.read_json.return_value = MOCK_USER_DATA - print("Hello",MOCK_USER_DATA) + print("Hello", MOCK_USER_DATA) delete.helper.write_json.return_value = True MOCK_Message_data = create_message("Hello") mc = mock_telebot.return_value From 0d9671bbd5ba6979ea7c3ab0745d242c311d3c57 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sat, 30 Oct 2021 21:43:50 -0400 Subject: [PATCH 37/56] Adding test cases for eedit functionality --- test/test_edit.py | 63 +++++++++++++++++++++++++++++++++++++++++++++ test/test_helper.py | 8 ++++++ 2 files changed, 71 insertions(+) create mode 100644 test/test_edit.py diff --git a/test/test_edit.py b/test/test_edit.py new file mode 100644 index 000000000..a2ef277b8 --- /dev/null +++ b/test/test_edit.py @@ -0,0 +1,63 @@ +from mock import patch +from telebot import types +from code import edit + + +@patch('telebot.telebot') +def test_run(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("hello from test run!") + edit.run(message, mc) + assert mc.reply_to.called + + +@patch('telebot.telebot') +def test_select_category_to_be_updated(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("hello from testing!") + edit.select_category_to_be_updated(message, mc) + assert mc.reply_to.called + + +@patch('telebot.telebot') +def test_select_category_selection_no_matching_choices(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = [] + mc.reply_to.return_value = True + mocker.patch.object(edit, 'helper') + edit.helper.getChoices().return_value = None + message = create_message("hello from testing!") + edit.select_category_to_be_updated(message, mc) + assert mc.reply_to.called + + +@patch('telebot.telebot') +def test_post_category_selection_no_matching_category(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = [] + mc.reply_to.return_value = True + mocker.patch.object(edit, 'helper') + edit.helper.getSpendCategories.return_value = None + message = create_message("hello from testing!") + edit.select_category_to_be_updated(message, mc) + assert mc.reply_to.called + + +@patch('telebot.telebot') +def test_post_amount_input_nonworking(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + mc.reply_to.return_value = True + mocker.patch.object(edit, 'helper') + edit.helper.validate_entered_amount.return_value = 0 + message = create_message("hello from testing!") + edit.select_category_to_be_updated(message, mc) + assert mc.reply_to.called + + +def create_message(text): + params = {'messagebody': text} + chat = types.User(11, False, 'test') + return types.Message(1, None, None, chat, 'text', params, "") diff --git a/test/test_helper.py b/test/test_helper.py index e63412fb6..a13bf598f 100644 --- a/test/test_helper.py +++ b/test/test_helper.py @@ -204,3 +204,11 @@ def test_getMonthFormat(): assert True else: assert False, 'expected month format are not returned' + + +def test_getChoices(): + result = helper.getChoices() + if result == helper.choices: + assert True + else: + assert False, 'expected choices are not returned' \ No newline at end of file From a1bb0d076d2780586353ffd6df9a5cefa4474c6f Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sat, 30 Oct 2021 21:47:17 -0400 Subject: [PATCH 38/56] Adding test cases for eedit functionality --- code/edit.py | 30 +++++++++++++++--------------- code/helper.py | 6 +++++- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/code/edit.py b/code/edit.py index c3b0fb2bd..58f91164e 100644 --- a/code/edit.py +++ b/code/edit.py @@ -9,7 +9,7 @@ def run(m, bot): if str(chat_id) in user_list: info = bot.reply_to(m, "Please enter the date and category of the transaction you made (Eg: 01-Mar-2021,Transport)") - bot.register_next_step_handler(info, edit2, bot, user_list) + bot.register_next_step_handler(info, select_category_to_be_updated, bot) else: bot.reply_to(chat_id, "No data found") @@ -17,15 +17,14 @@ def run(m, bot): i_edit = -1 -def edit2(m, bot, user_list): - print("Inside edit 2") +def select_category_to_be_updated(m, bot): global i_edit i_edit = -1 chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) info = m.text date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" - info = info.split(',') + info = [""] if info is None else info.split(',') x = re.search(date_format, info[0]) if x is None: bot.reply_to(m, "The date is incorrect") @@ -33,21 +32,19 @@ def edit2(m, bot, user_list): markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 - choices = ['Date', 'Category', 'Cost'] - for c in choices: + + for c in helper.getChoices(): markup.add(c) - print("Outside record:") for record in data_edit: i_edit = i_edit + 1 record = record.split(',') if info[0] == record[0][0:11] and str(info[1]).strip() == str(record[1]).strip(): - print("Inside what do u want to update") choice = bot.reply_to(m, "What do you want to update?", reply_markup=markup) - bot.register_next_step_handler(choice, edit3, bot, user_list) + bot.register_next_step_handler(choice, enter_updated_data, bot) break -def edit3(m, bot, user_list): +def enter_updated_data(m, bot): choice1 = m.text markup = types.ReplyKeyboardMarkup(one_time_keyboard=True) markup.row_width = 2 @@ -56,19 +53,20 @@ def edit3(m, bot, user_list): if choice1 == 'Date': new_date = bot.reply_to(m, "Please enter the new date (in dd-mmm-yyy format)") - bot.register_next_step_handler(new_date, edit_date, bot, user_list) + bot.register_next_step_handler(new_date, edit_date, bot) if choice1 == 'Category': new_cat = bot.reply_to(m, "Please select the new category", reply_markup=markup) - bot.register_next_step_handler(new_cat, edit_cat, bot, user_list) + bot.register_next_step_handler(new_cat, edit_cat, bot) if choice1 == 'Cost': new_cost = bot.reply_to(m, "Please type the new cost") - bot.register_next_step_handler(new_cost, edit_cost, bot, user_list) + bot.register_next_step_handler(new_cost, edit_cost, bot) def edit_date(m, bot, user_list): global i_edit + user_list = helper.read_json() new_date = m.text date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" chat_id = m.chat.id @@ -85,8 +83,9 @@ def edit_date(m, bot, user_list): bot.reply_to(m, "Date is updated") -def edit_cat(m, bot, user_list): +def edit_cat(m, bot): global i_edit + user_list = helper.read_json() chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) new_cat = m.text @@ -98,8 +97,9 @@ def edit_cat(m, bot, user_list): bot.reply_to(m, "Category is updated") -def edit_cost(m, bot, user_list): +def edit_cost(m, bot): global i_edit + user_list = helper.read_json() new_cost = m.text chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) diff --git a/code/helper.py b/code/helper.py index a5528db79..a87a152b1 100644 --- a/code/helper.py +++ b/code/helper.py @@ -3,7 +3,7 @@ import os spend_categories = ['Food', 'Groceries', 'Utilities', 'Transport', 'Shopping', 'Miscellaneous'] - +choices = ['Date', 'Category', 'Cost'] spend_display_option = ['Day', 'Month'] # set of implemented commands and their description @@ -84,3 +84,7 @@ def getTimeFormat(): def getMonthFormat(): return monthFormat + +def getChoices(): + return choices + From c806db7daabed1f14f3a3c7273effb9d9e48ced8 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sat, 30 Oct 2021 21:55:44 -0400 Subject: [PATCH 39/56] Adding test cases for edit functionality build fix --- code/helper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/code/helper.py b/code/helper.py index a87a152b1..e47460bf0 100644 --- a/code/helper.py +++ b/code/helper.py @@ -85,6 +85,7 @@ def getTimeFormat(): def getMonthFormat(): return monthFormat + def getChoices(): return choices From 67d9958fb99100ef101c283d849944899f29a094 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sat, 30 Oct 2021 22:00:42 -0400 Subject: [PATCH 40/56] Test cases for edit functionality build fix --- code/helper.py | 1 - test/test_helper.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/code/helper.py b/code/helper.py index e47460bf0..4d9114ea0 100644 --- a/code/helper.py +++ b/code/helper.py @@ -88,4 +88,3 @@ def getMonthFormat(): def getChoices(): return choices - diff --git a/test/test_helper.py b/test/test_helper.py index a13bf598f..6f1b5611e 100644 --- a/test/test_helper.py +++ b/test/test_helper.py @@ -211,4 +211,4 @@ def test_getChoices(): if result == helper.choices: assert True else: - assert False, 'expected choices are not returned' \ No newline at end of file + assert False, 'expected choices are not returned' From 4c205c6c78b9e220d54fd4cb9c34b265e71ac217 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sun, 31 Oct 2021 16:02:08 -0400 Subject: [PATCH 41/56] Edit functionality - Code coverage issue fix --- code/edit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/edit.py b/code/edit.py index 58f91164e..27402a619 100644 --- a/code/edit.py +++ b/code/edit.py @@ -23,7 +23,7 @@ def select_category_to_be_updated(m, bot): chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) info = m.text - date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + date_format = r"^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" info = [""] if info is None else info.split(',') x = re.search(date_format, info[0]) if x is None: @@ -68,7 +68,7 @@ def edit_date(m, bot, user_list): global i_edit user_list = helper.read_json() new_date = m.text - date_format = "^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + date_format = r"^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) x1 = re.search(date_format, new_date) From 6bfb0fc365344ad3bda45dcb7037d49599f87781 Mon Sep 17 00:00:00 2001 From: zedunaid Date: Sun, 31 Oct 2021 16:22:34 -0400 Subject: [PATCH 42/56] Edit functionality - Code coverage issue fix --- code/edit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/edit.py b/code/edit.py index 27402a619..c6bf9f738 100644 --- a/code/edit.py +++ b/code/edit.py @@ -23,7 +23,7 @@ def select_category_to_be_updated(m, bot): chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) info = m.text - date_format = r"^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + date_format = r'^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$' info = [""] if info is None else info.split(',') x = re.search(date_format, info[0]) if x is None: @@ -68,7 +68,7 @@ def edit_date(m, bot, user_list): global i_edit user_list = helper.read_json() new_date = m.text - date_format = r"^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$" + date_format = r'^(([0][1-9])|([1-2][0-9])|([3][0-1]))\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\-\d{4}$' chat_id = m.chat.id data_edit = helper.getUserHistory(chat_id) x1 = re.search(date_format, new_date) From 24fdf4135308eaa34135b93458695d2b98ee4a2b Mon Sep 17 00:00:00 2001 From: ASHOK KUMAR S Date: Sun, 31 Oct 2021 19:31:50 -0400 Subject: [PATCH 43/56] Update build badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 068fd8b5a..ae4847ba3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ![GitHub contributors](https://img.shields.io/github/contributors/deekay2310/SE21_HW2B_Group6) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5542548.svg)](https://doi.org/10.5281/zenodo.5542548) [![Platform](https://img.shields.io/badge/Platform-Telegram-blue)](https://desktop.telegram.org/) -[![Build Status](https://app.travis-ci.com/deekay2310/MyDollarBot.svg?branch=main)](https://app.travis-ci.com/github/deekay2310/MyDollarBot) +[![Build Status](https://app.travis-ci.com/sak007/MyDollarBot.svg?branch=backlogs)](https://app.travis-ci.com/github/sak007/MyDollarBot) [![codecov](https://codecov.io/gh/sak007/MyDollarBot/branch/main/graph/badge.svg?token=5AYMR8MNMP)](https://codecov.io/gh/sak007/MyDollarBot) [![GitHub issues](https://img.shields.io/github/issues/sak007/MyDollarBot)](https://github.com/sak007/MyDollarBot/issues?q=is%3Aopen+is%3Aissue) [![GitHub closed issues](https://img.shields.io/github/issues-closed/sak007/MyDollarBot)](https://github.com/sak007/MyDollarBot/issues?q=is%3Aissue+is%3Aclosed) From 08d2b3e3b02ac14a52b5693630704f27054173e0 Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 21:23:18 -0400 Subject: [PATCH 44/56] added a test to test_add.py --- test/test_add.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_add.py b/test/test_add.py index e8bd5870e..0ca5abdfa 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -46,6 +46,19 @@ def test_post_amount_input_working(mock_telebot, mocker): assert(mc.send_message.called) +@patch('telebot.telebot') +def test_post_amount_input_working_withdata(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + mocker.patch.object(add, 'helper') + add.helper.validate_entered_amount.return_value = 10 + add.helper.write_json.return_value = True + + message = create_message("hello from testing!") + add.post_category_selection(message, mc) + assert(mc.send_message.called) + + @patch('telebot.telebot') def test_post_amount_input_nonworking(mock_telebot, mocker): mc = mock_telebot.return_value From c4ecdef27a0c1cb7bc494e1d39e5ac57e79dbe11 Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 22:02:06 -0400 Subject: [PATCH 45/56] added test in test_add for add record --- test/test_add.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/test/test_add.py b/test/test_add.py index 0ca5abdfa..35db7e8fb 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -1,3 +1,5 @@ +import os +import json from mock.mock import patch from telebot import types from code import add @@ -72,16 +74,41 @@ def test_post_amount_input_nonworking(mock_telebot, mocker): assert(mc.reply_to.called) -def test_add_user_record(mocker): +def test_add_user_record_nonworking(mocker): mocker.patch.object(add, 'helper') add.helper.read_json.return_value = {} addeduserrecord = add.add_user_record(1, "record : test") - print(addeduserrecord) assert(addeduserrecord) +def test_add_user_record_working(mocker): + MOCK_USER_DATA = test_read_json() + mocker.patch.object(add, 'helper') + add.helper.read_json.return_value = MOCK_USER_DATA + print(len(MOCK_USER_DATA)) + addeduserrecord = add.add_user_record(1, "record : test") + print(len(MOCK_USER_DATA), " here") + if(len(MOCK_USER_DATA) + 1 == len(addeduserrecord)): + assert True + + def create_message(text): params = {'messagebody': text} chat = types.User(11, False, 'test') return types.Message(1, None, None, chat, 'text', params, "") + + +def test_read_json(): + try: + if not os.path.exists('./test/dummy_expense_record.json'): + with open('./test/dummy_expense_record.json', 'w') as json_file: + json_file.write('{}') + return json.dumps('{}') + elif os.stat('./test/dummy_expense_record.json').st_size != 0: + with open('./test/dummy_expense_record.json') as expense_record: + expense_record_data = json.load(expense_record) + return expense_record_data + + except FileNotFoundError: + print("---------NO RECORDS FOUND---------") \ No newline at end of file From 5b4c31516524f46dc25948660ad733f19b6c9ddb Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 22:02:46 -0400 Subject: [PATCH 46/56] fixed flake8 issue added test_add test case --- test/test_add.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_add.py b/test/test_add.py index 35db7e8fb..cf3055fd7 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -111,4 +111,4 @@ def test_read_json(): return expense_record_data except FileNotFoundError: - print("---------NO RECORDS FOUND---------") \ No newline at end of file + print("---------NO RECORDS FOUND---------") From 9ece4b1432ddd5a6e0bf493bfc38928c3770a0fe Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 22:07:22 -0400 Subject: [PATCH 47/56] fixed flake8 issue --- test/test_add.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_add.py b/test/test_add.py index cf3055fd7..49dc116db 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -77,7 +77,6 @@ def test_post_amount_input_nonworking(mock_telebot, mocker): def test_add_user_record_nonworking(mocker): mocker.patch.object(add, 'helper') add.helper.read_json.return_value = {} - addeduserrecord = add.add_user_record(1, "record : test") assert(addeduserrecord) @@ -86,9 +85,7 @@ def test_add_user_record_working(mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(add, 'helper') add.helper.read_json.return_value = MOCK_USER_DATA - print(len(MOCK_USER_DATA)) addeduserrecord = add.add_user_record(1, "record : test") - print(len(MOCK_USER_DATA), " here") if(len(MOCK_USER_DATA) + 1 == len(addeduserrecord)): assert True From b54aaad59b7ea02a1066b68f45dda5855e9ede92 Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 22:44:51 -0400 Subject: [PATCH 48/56] fixed tests in test_add.py --- test/test_add.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/test/test_add.py b/test/test_add.py index 49dc116db..ea6db7edf 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -3,6 +3,12 @@ from mock.mock import patch from telebot import types from code import add +from mock import ANY + + +dateFormat = '%d-%b-%Y' +timeFormat = '%H:%M' +monthFormat = '%b-%Y' @patch('telebot.telebot') @@ -52,12 +58,17 @@ def test_post_amount_input_working(mock_telebot, mocker): def test_post_amount_input_working_withdata(mock_telebot, mocker): mc = mock_telebot.return_value mc.send_message.return_value = True - mocker.patch.object(add, 'helper') + mocker.patch.object(add, 'helper') add.helper.validate_entered_amount.return_value = 10 add.helper.write_json.return_value = True + add.helper.getDateFormat.return_value = dateFormat + add.helper.getTimeFormat.return_value = timeFormat + + mocker.patch.object(add, 'option') + add.option.return_value = {11, "here"} message = create_message("hello from testing!") - add.post_category_selection(message, mc) + add.post_amount_input(message, mc) assert(mc.send_message.called) @@ -68,12 +79,33 @@ def test_post_amount_input_nonworking(mock_telebot, mocker): mc.reply_to.return_value = True mocker.patch.object(add, 'helper') add.helper.validate_entered_amount.return_value = 0 - message = create_message("hello from testing!") - add.post_category_selection(message, mc) + add.post_amount_input(message, mc) assert(mc.reply_to.called) +@patch('telebot.telebot') +def test_post_amount_input_working_withdata_chatid(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.send_message.return_value = True + mocker.patch.object(add, 'helper') + add.helper.validate_entered_amount.return_value = 10 + add.helper.write_json.return_value = True + add.helper.getDateFormat.return_value = dateFormat + add.helper.getTimeFormat.return_value = timeFormat + + mocker.patch.object(add, 'option') + add.option = {11, "here"} + test_option = {} + test_option[11] = "here" + add.option = test_option + + message = create_message("hello from testing!") + add.post_amount_input(message, mc) + assert(mc.send_message.called) + assert(mc.send_message.called_with(11, ANY)) + + def test_add_user_record_nonworking(mocker): mocker.patch.object(add, 'helper') add.helper.read_json.return_value = {} From 901360f74d476e22814ea21e3fec01fa09a401b6 Mon Sep 17 00:00:00 2001 From: Athithya Date: Sun, 31 Oct 2021 22:46:43 -0400 Subject: [PATCH 49/56] fixed flake8 issues --- test/test_add.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_add.py b/test/test_add.py index ea6db7edf..c275076ed 100644 --- a/test/test_add.py +++ b/test/test_add.py @@ -58,7 +58,7 @@ def test_post_amount_input_working(mock_telebot, mocker): def test_post_amount_input_working_withdata(mock_telebot, mocker): mc = mock_telebot.return_value mc.send_message.return_value = True - mocker.patch.object(add, 'helper') + mocker.patch.object(add, 'helper') add.helper.validate_entered_amount.return_value = 10 add.helper.write_json.return_value = True add.helper.getDateFormat.return_value = dateFormat @@ -88,7 +88,7 @@ def test_post_amount_input_nonworking(mock_telebot, mocker): def test_post_amount_input_working_withdata_chatid(mock_telebot, mocker): mc = mock_telebot.return_value mc.send_message.return_value = True - mocker.patch.object(add, 'helper') + mocker.patch.object(add, 'helper') add.helper.validate_entered_amount.return_value = 10 add.helper.write_json.return_value = True add.helper.getDateFormat.return_value = dateFormat From 6918c86f91d887354eb28d08bad70c69731f1051 Mon Sep 17 00:00:00 2001 From: Sri Athithya Kruth Babu Date: Mon, 1 Nov 2021 10:57:33 +0530 Subject: [PATCH 50/56] Updated README.md with the latest run instructions Updated README.md with the latest run instructions, and edited the running instructions to make them concise. Changed image size to improve aesthetics. --- README.md | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index ae4847ba3..15501e3fb 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ # TrackMyDollar

-Expense tracking made easy!


![MIT license](https://img.shields.io/badge/License-MIT-green.svg) +[![Platform](https://img.shields.io/badge/Platform-Telegram-blue)](https://desktop.telegram.org/) ![GitHub](https://img.shields.io/badge/Language-Python-blue.svg) -![GitHub contributors](https://img.shields.io/github/contributors/deekay2310/SE21_HW2B_Group6) + +![GitHub contributors](https://img.shields.io/github/contributors/sak007/project-X) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5542548.svg)](https://doi.org/10.5281/zenodo.5542548) -[![Platform](https://img.shields.io/badge/Platform-Telegram-blue)](https://desktop.telegram.org/) + [![Build Status](https://app.travis-ci.com/sak007/MyDollarBot.svg?branch=backlogs)](https://app.travis-ci.com/github/sak007/MyDollarBot) [![codecov](https://codecov.io/gh/sak007/MyDollarBot/branch/main/graph/badge.svg?token=5AYMR8MNMP)](https://codecov.io/gh/sak007/MyDollarBot) [![GitHub issues](https://img.shields.io/github/issues/sak007/MyDollarBot)](https://github.com/sak007/MyDollarBot/issues?q=is%3Aopen+is%3Aissue) @@ -36,46 +38,43 @@ https://user-images.githubusercontent.com/15325746/135395315-e234dc5e-d891-470a- The below instructions can be followed in order to set-up this bot at your end in a span of few minutes! Let's get started: -1. This installation guide assumes that you have already installed Python (Python3 would be preferred) - -2. Clone this repository to your local system at a suitable directory/location of your choice - -3. Start a terminal session, and navigate to the directory where the repo has been cloned +1. This installation guide assumes that you have already installed Python (Python3 would be preferred) and Telegram web or Desktop. Clone this repository to your local system. -4. Run the following command to install the required dependencies: +2. Start a terminal session in the directory where the project has been cloned. Run the following command to install the required dependencies: ``` pip install -r requirements.txt ``` -5. Download and install the Telegram desktop application for your system from the following site: https://desktop.telegram.org/ -6. Once you login to your Telegram account, search for "BotFather" in Telegram. Click on "Start" --> enter the following command: +3. In Telegram, search for "BotFather". Click on "Start", and enter the following command: ``` /newbot ``` -7. Follow the instructions on screen and choose a name for your bot. Post this, select a username for your bot that ends with "bot" (as per the instructions on your Telegram screen) +Follow the instructions on screen and choose a name for your bot. After this, select a username for your bot that ends with "bot". -8. BotFather will now confirm the creation of your bot and provide a TOKEN to access the HTTP API - copy this token for future use. +4. BotFather will now confirm the creation of your bot and provide a TOKEN to access the HTTP API - copy and save this token for future use. -9. In the directory where this repo has been cloned, navigate to the "code" folder and open the "code.py" file. This file consists of a variable by the name "api_token". Paste the token copied in step 8 in the placeholder provided for this variable: +5. In the directory where this repo has been cloned, please run the below command to execute a bash script to run the Telegram Bot: ``` - api_token = "INSERT API KEY HERE" + ./run.sh ``` -10. In the Telegram app, search for your newly created bot by entering the username and open the same. Once this is done, go back to the terminal session. Navigate to the directory containing the "code.py" file and run the following command: +(OR) ``` - python code.py + bash run.sh ``` -11. A successful run will generate a message on your terminal that says "TeleBot: Started polling." -12. Post this, navigate to your bot on Telegram, enter the "/start" or "/menu" command, and you are all set to track your expenses! +Please note that it will ask you to paste the API token you received from Telegram in step 4. +A successful run will generate a message on your terminal that says "TeleBot: Started polling." +6. In the Telegram app, search for your newly created bot by entering the username and open the same. Now, on Telegram, enter the "/start" or "/menu" command, and you are all set to track your expenses! +# Notes: +You can download and install the Telegram desktop application for your system from the following site: https://desktop.telegram.org/
-

--------------------------------------------------------------------------------------------------

Title:'Track My Dollar'

-

Version: '1.0'

+

Version: '1.5'

Description: 'An easy to use Telegram Bot to track everyday expenses'

-

Authors:'Dev, Prakruthi, Radhika, Rohan, Sunidhi'

-

--------------------------------------------------------------------------------------------------

+

Authors(Iteration 1.5):'Athithya, Subramanian, Ashok, Zunaid, Rithik'

+

Authors(Iteration 1):'Dev, Prakruthi, Radhika, Rohan, Sunidhi'

From 010a46322e833d7b56ce2e0f4e1193642811dcfd Mon Sep 17 00:00:00 2001 From: Rithik Jain Date: Mon, 1 Nov 2021 22:12:03 -0400 Subject: [PATCH 51/56] Added Test for display --- test/test_display.py | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/test_display.py diff --git a/test/test_display.py b/test/test_display.py new file mode 100644 index 000000000..70a1fb234 --- /dev/null +++ b/test/test_display.py @@ -0,0 +1,74 @@ +from mock import patch +from telebot import types +from code import display + + +@patch('telebot.telebot') +def test_run(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("hello from test run!") + display.run(message, mc) + assert mc.send_message.called + +@patch('telebot.telebot') +def test_no_data_available(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("/spendings") + display.run(message, mc) + assert mc.send_message.called + +@patch('telebot.telebot') +def test_invalid_format(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("luster") + try: + display.display_total(message, mc) + #In this case it accepted an unusable format, fail the test + assert False + except Exception: + assert True + +@patch('telebot.telebot') +def test_valid_format(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("Month") + try: + display.display_total(message, mc) + assert True + except Exception: + #In this case it did not accept a usable format, fail the test + assert False +@patch('telebot.telebot') +def test_valid_format_day(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("Day") + try: + display.display_total(message, mc) + assert True + except Exception: + #In this case it did not accept a usable format, fail the test + assert False + +@patch('telebot.telebot') +def test_spending_display(mock_telebot, mocker): + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("Day") + message.text = "Day" + try: + display.display_total(message, mc) + assert False + except Exception: + #In this case there where no records + assert True + + +def create_message(text): + params = {'messagebody': text} + chat = types.User(11, False, 'test') + return types.Message(894127939, None, None, chat, 'text', params, "") From 3561d8142cf5fa73950a0d0ee025f791bd613591 Mon Sep 17 00:00:00 2001 From: Rithik Jain Date: Mon, 1 Nov 2021 22:38:13 -0400 Subject: [PATCH 52/56] Fixed the build error --- test/test_display.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/test_display.py b/test/test_display.py index 70a1fb234..703983b9d 100644 --- a/test/test_display.py +++ b/test/test_display.py @@ -11,6 +11,7 @@ def test_run(mock_telebot, mocker): display.run(message, mc) assert mc.send_message.called + @patch('telebot.telebot') def test_no_data_available(mock_telebot, mocker): mc = mock_telebot.return_value @@ -19,6 +20,7 @@ def test_no_data_available(mock_telebot, mocker): display.run(message, mc) assert mc.send_message.called + @patch('telebot.telebot') def test_invalid_format(mock_telebot, mocker): mc = mock_telebot.return_value @@ -26,11 +28,12 @@ def test_invalid_format(mock_telebot, mocker): message = create_message("luster") try: display.display_total(message, mc) - #In this case it accepted an unusable format, fail the test +#In this case it accepted an unusable format, fail the test assert False except Exception: assert True + @patch('telebot.telebot') def test_valid_format(mock_telebot, mocker): mc = mock_telebot.return_value @@ -40,8 +43,10 @@ def test_valid_format(mock_telebot, mocker): display.display_total(message, mc) assert True except Exception: - #In this case it did not accept a usable format, fail the test +#In this case it did not accept a usable format, fail the test assert False + + @patch('telebot.telebot') def test_valid_format_day(mock_telebot, mocker): mc = mock_telebot.return_value @@ -51,9 +56,10 @@ def test_valid_format_day(mock_telebot, mocker): display.display_total(message, mc) assert True except Exception: - #In this case it did not accept a usable format, fail the test +#In this case it did not accept a usable format, fail the test assert False + @patch('telebot.telebot') def test_spending_display(mock_telebot, mocker): mc = mock_telebot.return_value @@ -64,7 +70,7 @@ def test_spending_display(mock_telebot, mocker): display.display_total(message, mc) assert False except Exception: - #In this case there where no records +#In this case there where no records assert True From c9b0681ed7c24d899fd36f108c412be301bd28cb Mon Sep 17 00:00:00 2001 From: Rithik Date: Thu, 4 Nov 2021 01:21:50 -0400 Subject: [PATCH 53/56] Fixed the build issue --- test/test_display.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/test_display.py b/test/test_display.py index 703983b9d..c42c09915 100644 --- a/test/test_display.py +++ b/test/test_display.py @@ -28,7 +28,6 @@ def test_invalid_format(mock_telebot, mocker): message = create_message("luster") try: display.display_total(message, mc) -#In this case it accepted an unusable format, fail the test assert False except Exception: assert True @@ -43,7 +42,6 @@ def test_valid_format(mock_telebot, mocker): display.display_total(message, mc) assert True except Exception: -#In this case it did not accept a usable format, fail the test assert False @@ -56,7 +54,6 @@ def test_valid_format_day(mock_telebot, mocker): display.display_total(message, mc) assert True except Exception: -#In this case it did not accept a usable format, fail the test assert False @@ -70,7 +67,6 @@ def test_spending_display(mock_telebot, mocker): display.display_total(message, mc) assert False except Exception: -#In this case there where no records assert True From 861194ca28c4f607899ef0aa4195337f56c8eaa7 Mon Sep 17 00:00:00 2001 From: Rithik Date: Thu, 4 Nov 2021 01:56:22 -0400 Subject: [PATCH 54/56] Improved coverage to fix build --- test/test_display.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/test_display.py b/test/test_display.py index c42c09915..4ca175ecd 100644 --- a/test/test_display.py +++ b/test/test_display.py @@ -1,3 +1,5 @@ +import os +import json from mock import patch from telebot import types from code import display @@ -58,19 +60,38 @@ def test_valid_format_day(mock_telebot, mocker): @patch('telebot.telebot') -def test_spending_display(mock_telebot, mocker): +def test_spending_display_working(mock_telebot, mocker): + + MOCK_USER_DATA = test_read_json() + mocker.patch.object(display, 'helper') + display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] + display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getDateFormat.return_value = '%d-%b-%Y' + display.helper.getMonthFormat.return_value = '%b-%Y' mc = mock_telebot.return_value mc.reply_to.return_value = True message = create_message("Day") message.text = "Day" - try: - display.display_total(message, mc) - assert False - except Exception: - assert True + display.display_total(message, mc) + assert True def create_message(text): params = {'messagebody': text} chat = types.User(11, False, 'test') return types.Message(894127939, None, None, chat, 'text', params, "") + + +def test_read_json(): + try: + if not os.path.exists('./test/dummy_expense_record.json'): + with open('./test/dummy_expense_record.json', 'w') as json_file: + json_file.write('{}') + return json.dumps('{}') + elif os.stat('./test/dummy_expense_record.json').st_size != 0: + with open('./test/dummy_expense_record.json') as expense_record: + expense_record_data = json.load(expense_record) + return expense_record_data + + except FileNotFoundError: + print("---------NO RECORDS FOUND---------") From 5a21c120c04d8137353712dbd5fc735b4de8ecef Mon Sep 17 00:00:00 2001 From: Rithik Date: Thu, 4 Nov 2021 10:05:59 -0400 Subject: [PATCH 55/56] Added coverage to display.py --- test/test_display.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/test/test_display.py b/test/test_display.py index 4ca175ecd..c76e53af1 100644 --- a/test/test_display.py +++ b/test/test_display.py @@ -73,7 +73,41 @@ def test_spending_display_working(mock_telebot, mocker): message = create_message("Day") message.text = "Day" display.display_total(message, mc) - assert True + assert mc.send_message.called + + +@patch('telebot.telebot') +def test_spending_display_month(mock_telebot, mocker): + + MOCK_USER_DATA = test_read_json() + mocker.patch.object(display, 'helper') + display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] + display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getDateFormat.return_value = '%d-%b-%Y' + display.helper.getMonthFormat.return_value = '%b-%Y' + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("Month") + message.text = "Month" + display.display_total(message, mc) + assert mc.send_message.called + + +@patch('telebot.telebot') +def test_spending_display_luster(mock_telebot, mocker): + + MOCK_USER_DATA = test_read_json() + mocker.patch.object(display, 'helper') + display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] + display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getDateFormat.return_value = '%d-%b-%Y' + display.helper.getMonthFormat.return_value = '%b-%Y' + mc = mock_telebot.return_value + mc.reply_to.return_value = True + message = create_message("Luster") + message.text = "Luster" + display.display_total(message, mc) + assert not mc.send_message.called def create_message(text): From 0a66b9c10f5d66f69bd061055200d2975c980034 Mon Sep 17 00:00:00 2001 From: Rithik Date: Thu, 4 Nov 2021 10:20:11 -0400 Subject: [PATCH 56/56] Improved coverage for test_display.py --- test/test_display.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/test_display.py b/test/test_display.py index c76e53af1..86488575f 100644 --- a/test/test_display.py +++ b/test/test_display.py @@ -60,54 +60,57 @@ def test_valid_format_day(mock_telebot, mocker): @patch('telebot.telebot') -def test_spending_display_working(mock_telebot, mocker): +def test_spending_run_working(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(display, 'helper') display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] - display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getSpendDisplayOptions.return_value = [ + "Day", "Month"] display.helper.getDateFormat.return_value = '%d-%b-%Y' display.helper.getMonthFormat.return_value = '%b-%Y' mc = mock_telebot.return_value mc.reply_to.return_value = True message = create_message("Day") message.text = "Day" - display.display_total(message, mc) - assert mc.send_message.called + display.run(message, mc) + assert not mc.send_message.called @patch('telebot.telebot') -def test_spending_display_month(mock_telebot, mocker): +def test_spending_display_working(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(display, 'helper') display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] - display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getSpendDisplayOptions.return_value = [ + "Day", "Month"] display.helper.getDateFormat.return_value = '%d-%b-%Y' display.helper.getMonthFormat.return_value = '%b-%Y' mc = mock_telebot.return_value mc.reply_to.return_value = True - message = create_message("Month") - message.text = "Month" + message = create_message("Day") + message.text = "Day" display.display_total(message, mc) assert mc.send_message.called @patch('telebot.telebot') -def test_spending_display_luster(mock_telebot, mocker): +def test_spending_display_month(mock_telebot, mocker): MOCK_USER_DATA = test_read_json() mocker.patch.object(display, 'helper') display.helper.getUserHistory.return_value = MOCK_USER_DATA["894127939"] - display.helper.getSpendDisplayOptions.return_value = ["Day", "Month"] + display.helper.getSpendDisplayOptions.return_value = [ + "Day", "Month"] display.helper.getDateFormat.return_value = '%d-%b-%Y' display.helper.getMonthFormat.return_value = '%b-%Y' mc = mock_telebot.return_value mc.reply_to.return_value = True - message = create_message("Luster") - message.text = "Luster" + message = create_message("Month") + message.text = "Month" display.display_total(message, mc) - assert not mc.send_message.called + assert mc.send_message.called def create_message(text):