diff --git a/README.md b/README.md index 3cf3e00..a01862f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Budget -Budget helps you control your Mastodon's server bills and donations and share current financial status with your users by posting them via this Budget bot. +Budget helps you control your Mastodon's server bills and donations and share current financial status with your users by posting them via the publisher bot. ### Dependencies @@ -17,11 +17,9 @@ Within Python Virtual Environment: 3. Run `python setup.py` to get your Mastodon's bot account tokens and to be able to post your server's financial status. -4. Run `python addincome.py` to add your donations. +4. Run `python budget.py` to manage or list your bills and donations. -5. Run `python addbill.py` to add your server or domain bills. +5. Run `python addfee.py` to add your regular fees. -6. Run `python addfee.py` to add your regular fees. - -7. Use your favourite scheduling method to set `python budget.py` to run regularly. It will post your finances to your fediverse server. +6. Use your favourite scheduling method to set `python publisher.py` to run regularly. It will post your finances to your fediverse server. diff --git a/publisher.py b/publisher.py new file mode 100644 index 0000000..02b3d04 --- /dev/null +++ b/publisher.py @@ -0,0 +1,221 @@ +import sys +import os +import os.path +import re +from datetime import datetime, timedelta +from mastodon import Mastodon +import psycopg2 + +def get_bills(): + + current_year = now.year + + bills = 0 + + try: + + conn = None + + conn = psycopg2.connect(database = budget_db, user = budget_db_user, password = "", host = "/var/run/postgresql", port = "5432") + + cur = conn.cursor() + + cur.execute("select sum (domain) + sum(server) + sum(backup) + sum(fileserver) +sum(setup) from bills where date_part('year', datetime) = (%s)", (current_year,)) + + row = cur.fetchone() + + if row[0] != None: + + bills = row[0] + + cur.close() + + return bills + + except (Exception, psycopg2.DatabaseError) as error: + + sys.exit(error) + + finally: + + if conn is not None: + + conn.close() + +def get_donations(): + + current_year = now.year + + donations = 0 + + try: + + conn = None + + conn = psycopg2.connect(database = budget_db, user = budget_db_user, password = "", host = "/var/run/postgresql", port = "5432") + + cur = conn.cursor() + + cur.execute("select sum (donations) + sum(owner) from incomes where date_part('year', datetime) = (%s)", (current_year,)) + + row = cur.fetchone() + + if row[0] != None: + + donations = row[0] + + else: + + donations = 0 + + cur.close() + + return donations + + except (Exception, psycopg2.DatabaseError) as error: + + sys.exit(error) + + finally: + + if conn is not None: + + conn.close() + +def get_fixed_fees(): + + fees_desc_lst = [] + + fees_types_lst = [] + + fees_lst = [] + + + try: + + conn = None + + conn = psycopg2.connect(database = budget_db, user = budget_db_user, password = "", host = "/var/run/postgresql", port = "5432") + + cur = conn.cursor() + + cur.execute("select fee_description, payment_type, fee from fees") + + rows = cur.fetchall() + + for row in rows: + + fees_desc_lst.append(row[0]) + + fees_types_lst.append(row[1]) + + fees_lst.append(row[2]) + + cur.close() + + return (fees_desc_lst, fees_types_lst, fees_lst) + + except (Exception, psycopg2.DatabaseError) as error: + + sys.exit(error) + + finally: + + if conn is not None: + + conn.close() + + +def mastodon(): + + # Load secrets from secrets file + secrets_filepath = "secrets/secrets.txt" + uc_client_id = get_parameter("uc_client_id", secrets_filepath) + uc_client_secret = get_parameter("uc_client_secret", secrets_filepath) + uc_access_token = get_parameter("uc_access_token", secrets_filepath) + + # Load configuration from config file + config_filepath = "config/config.txt" + mastodon_hostname = get_parameter("mastodon_hostname", config_filepath) + bot_username = get_parameter("bot_username", config_filepath) + + # Initialise Mastodon API + mastodon = Mastodon( + client_id = uc_client_id, + client_secret = uc_client_secret, + access_token = uc_access_token, + api_base_url = 'https://' + mastodon_hostname, + ) + + # Initialise access headers + headers={ 'Authorization': 'Bearer %s'%uc_access_token } + + return (mastodon, mastodon_hostname, bot_username) + +def db_config(): + + # Load db configuration from config file + config_filepath = "config/db_config.txt" + budget_db = get_parameter("budget_db", config_filepath) + budget_db_user = get_parameter("budget_db_user", config_filepath) + + return (budget_db, budget_db_user) + +def get_parameter( parameter, file_path ): + + if not os.path.isfile(file_path): + print("File %s not found, exiting."%file_path) + sys.exit(0) + + with open( file_path ) as f: + for line in f: + if line.startswith( parameter ): + return line.replace(parameter + ":", "").strip() + + print(file_path + " Missing parameter %s "%parameter) + sys.exit(0) + +############################################################################### +# main + +if __name__ == '__main__': + + mastodon, mastodon_hostname, bot_username = mastodon() + + budget_db, budget_db_user = db_config() + + now = datetime.now() + + donations = get_donations() + + bills = get_bills() + + fees_desc_lst, fees_types_lst, fees_lst = get_fixed_fees() + + toot_text = 'Finances of ' + mastodon_hostname + '\n\n' + + toot_text += 'Year: ' + str(now.year) + '\n' + + toot_text += '\n' + + toot_text += 'Server bills: ' + str(bills) + '€' + '\n' + + toot_text += 'Donations: ' + str(donations) + '€' + '\n\n' + + if donations != 0 and bills != 0: + + toot_text += '%: ' + str(round((donations * 100)/bills,2)) + '\n\n' + + i = 0 + + while i < len(fees_lst): + + toot_text += '\n' + str(fees_desc_lst[i]) + ': ' + str(fees_lst[i]) + ' (' + str(fees_types_lst[i]) + ')' + + i += 1 + + print(toot_text) + + mastodon.status_post(toot_text, in_reply_to_id=None) + +