Newer
Older
pan_au_chocolat / main.py
Francesco Mecca on 19 Jan 2020 4 KB fst
import secrets
import expenses
from expenses import SharedExpense, Debit, Credit
from db import Database

from telegram.ext import Updater
from telegram.ext import MessageHandler, Filters
from telegram.ext import CommandHandler
from parsimonious import ParseError

import logging
from enum import Enum
from functools import partial

Result = Enum('MsgResult', 'OK DENY ERROR')

logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S',
                    level=logging.INFO)

def log_chat_msg(result, update, additional_message=''):
    if type(additional_message) is None:
        additional_message = ''

    msg = f'{update.effective_chat.id}:{update.effective_chat.username} \
| {result} | "{update.message.text} | {additional_message}"'
    if result == Result.OK:
        logging.info(msg)
    elif result == Result.DENY:
        logging.info(msg)
    elif result == Result.ERROR:
        logging.error(msg)
    else:
        assert False

def authorized_ids_only(f):
    def invalid_id(update, context):
        context.bot.send_message(chat_id=update.effective_chat.id,
                                text="Sorry, you are not authorized to use this bot")

    def log_to_shared_group(context, msg):
        context.bot.send_message(chat_id=secrets.sharedgroup_id, text=msg)

    def decorated(*args, **kwargs):
        update, context = args[0], args[1]

        chat_id = update.effective_chat.id
        if chat_id in secrets.authorized_ids:
            try:
                log_msg = f(*args, **kwargs)
                log_chat_msg(Result.OK, update, additional_message=log_msg)

            except Exception as e:
                log_chat_msg(Result.ERROR, update, additional_message=str(e))

            finally:
                issuer = f'{update.effective_chat.username}'
                group_msg = f'{issuer} wrote: "{update.message.text}"'
                log_to_shared_group(context, group_msg)
                
        else:
            log_chat_msg(Result.DENY, update)
            return invalid_id(update, context) 
    return decorated 

@authorized_ids_only
def start(update, context):
    context.bot.send_message(chat_id=update.effective_chat.id, text="Quanti pan au chocolat hai comprato oggi?")

@authorized_ids_only
def help_command(update, context):
    msg = 'write (+|-) amount reason'
    context.bot.send_message(chat_id=update.effective_chat.id, text=msg)

@authorized_ids_only
def main_command(update, context, store):
    issuer = f'{update.effective_chat.id}:{update.effective_chat.username}'

    msg = update.message.text
    try:
        expense = expenses.parse(msg)
        store.write_expense(issuer, expense)

        msg_to_user = f'Wrote {expense} to the store'
        context.bot.send_message(chat_id=update.effective_chat.id, text=msg_to_user)
        return ''

    except ParseError as e:
        msg_to_user = f'Wrong format for msg'
        context.bot.send_message(chat_id=update.effective_chat.id, text=msg_to_user)
        return f'ParseError: {e}'

@authorized_ids_only
def report_command(update, context, store):
    print(update.effective_chat.id)
    report = store.report()
    msg = ''
    for issuer, (expenses, credits, debits) in report.items():
        msg += f'{issuer}: \n\
        Spese comuni: {expenses}, Crediti: {credits}, Debiti: {debits}\n'
    context.bot.send_message(chat_id=update.effective_chat.id, text=msg)

if __name__ == '__main__':
    updater = Updater(token=secrets.token, use_context=True)
    dispatcher = updater.dispatcher

    start_handler = CommandHandler('start', start)
    dispatcher.add_handler(start_handler)
    help_handler = CommandHandler('help', help_command)
    dispatcher.add_handler(help_handler)

    with Database('storage.bin') as store:
        main_with_store = lambda *args, **kwargs: main_command(*args, store, **kwargs)
        main_handler = MessageHandler(Filters.text, main_with_store)
        report_with_store = lambda *args, **kwargs: report_command(*args, store, **kwargs)
        dispatcher.add_handler(CommandHandler('report', report_with_store))
        dispatcher.add_handler(main_handler)

        updater.start_polling() # loop
        updater.idle() # avoid exiting the with block