86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
# stolat, cron-based birthday notifier
|
|
# Please run once per day.
|
|
# License: GPLv3 or later
|
|
import toml, os, importlib
|
|
from datetime import datetime
|
|
|
|
scripts = []
|
|
|
|
def get_current_path() -> str:
|
|
return os.path.dirname(os.path.abspath(__file__))
|
|
|
|
def load_config() -> dict:
|
|
|
|
# Try to get configuration from current_path/list.toml
|
|
try:
|
|
path = get_current_path()
|
|
config = toml.load(path + "/list.toml")
|
|
except:
|
|
print("Sorry! It seems like I can't access list.toml. Is it in the script's working directory?")
|
|
quit(-1)
|
|
|
|
return config
|
|
|
|
def calc_age(birth_date: str) -> int:
|
|
date_as_datetime = datetime.strptime(birth_date, "%Y-%m-%d")
|
|
delta = datetime.today() - date_as_datetime
|
|
return round(delta.days / 365.25)
|
|
|
|
def notify_user(birthday: dict, user: dict, actions: dict, days_till_birthday: int):
|
|
# print(f"Got {birthday}, {user} and actions {actions}.")
|
|
for channel in user['channels']:
|
|
|
|
for notify_action in actions:
|
|
|
|
if notify_action['id'] == channel:
|
|
|
|
# User wants to receive a notification through current notify_action
|
|
try:
|
|
module = importlib.import_module("scripts." + notify_action['name_of_script'][:notify_action['name_of_script'].rfind(".py")])
|
|
func = getattr(module, notify_action['startup_function'])
|
|
func("v1", user['user'], birthday['name'], calc_age(birthday['date']), days_till_birthday, birthday['date']) # v1-formatted function call
|
|
except Exception as e:
|
|
print(f"Error: failed executing {notify_action['startup_function']}() for {user['user']} ({birthday['name']}'s {calc_age(birthday['date'])}th birthday) :(\n"
|
|
f"Exception: {e}.")
|
|
|
|
def iterate_birthdays(config: dict):
|
|
|
|
badly_formatted_birthdays = 0
|
|
today = datetime.today()
|
|
for birthday in config['birthdays']:
|
|
|
|
try:
|
|
name = birthday['name']
|
|
birthdate_as_str = birthday['date']
|
|
birthdate = datetime.strptime(birthdate_as_str, "%Y-%m-%d")
|
|
to_notify = birthday['to_notify']
|
|
except Exception as e:
|
|
badly_formatted_birthdays += 1
|
|
continue
|
|
|
|
for user in config['preferences']:
|
|
|
|
birthdate_this_year = birthdate.replace(year=today.year)
|
|
|
|
# Safeguard against no additional reminders
|
|
if not user['additional_reminders']:
|
|
user['additional_reminders'] = []
|
|
|
|
# Consider the birthday as additional reminder
|
|
# This way we check the list once.
|
|
if (birthdate_this_year - today).days + 1 in user['additional_reminders']:
|
|
notify_user(birthday, user, config['actions'], (birthdate_this_year - today).days + 1)
|
|
|
|
if badly_formatted_birthdays > 0:
|
|
print(f"Warning: found {badly_formatted_birthdays} incorrectly formatted birth dates.\n"
|
|
f" They haven't been checked for possible birthdays. Please use ISO 8601.")
|
|
|
|
|
|
|
|
def main():
|
|
config = load_config()
|
|
iterate_birthdays(config)
|
|
|
|
if __name__ == "__main__":
|
|
main() |