From fbfb3afeb757f9633cce84cb600e249780743616 Mon Sep 17 00:00:00 2001 From: Florian Fischer Date: Fri, 28 Dec 2018 23:52:37 +0100 Subject: add suppport for legacy data stores and scheduled exec refactoring * monthly commands with days > 28 are executed on 28. * bug fixes in cancel * add support for python3 < 3.7 (date.fromisoformat) * add support for cmds in changes (cancel) --- geldschieberbot.py | 127 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/geldschieberbot.py b/geldschieberbot.py index 234ab68..99c308b 100644 --- a/geldschieberbot.py +++ b/geldschieberbot.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 -from datetime import datetime -from datetime import timedelta +from datetime import date, datetime, timedelta import json import os import subprocess @@ -28,6 +27,26 @@ else: "changes" : {}, } + # check if a legacy file layout is present + store_dir = os.path.dirname(state_file) + if os.path.isfile(os.path.join(store_dir, "balance.json")): + with open(os.path.join(store_dir, "balance.json"), "r") as f: + state["balance"] = json.load(f) + + with open(os.path.join(store_dir, "registration.json"), "r") as f: + state["name2num"] = json.load(f) + print(state["name2num"]) + for name in state["name2num"]: + state["num2name"][state["name2num"][name]] = name + print(state["num2name"]) + + with open(os.path.join(store_dir, "last_change.json"), "r") as f: + state["changes"] = json.load(f) + for num in state["changes"]: + name = state["num2name"][num] + state["changes"][name] = state["changes"[num] + del(state["changes"][num]) + balance = state["balance"] name2num = state["name2num"] num2name = state["num2name"] @@ -45,6 +64,9 @@ dry_run = False """Run without sending messages""" quiet = False +"""Should changes be recorded""" +record_changes = True + def record(recipient, donor, amount): """Apply changes to the balance""" @@ -239,7 +261,8 @@ def split(sender, args, msg): record(recipient, p, amount_per_person) change.append([recipient, p, amount_per_person]) - changes[recipient].append(change) + if record_changes and not dry_run: + changes[recipient].append(change) output += "New Balance:\n" output += create_summary(recipient) @@ -281,7 +304,8 @@ def transaction(sender, args, msg): if args[0] in ["!zieh", "!nimm"]: amount *= -1 - changes[sender].append([args, [sender, recipient, amount]]) + if record_changes and not dry_run: + changes[sender].append([args, [sender, recipient, amount]]) record(sender, recipient, amount) @@ -333,6 +357,9 @@ def tanken(sender, args, msg): else: output += p[0] + " not known. Please take care manually\n" + if record_changes and not dry_run: + changes[sender].append(change) + output += "New Balance:\n" output += create_summary(recipient) send(output) @@ -340,7 +367,6 @@ def tanken(sender, args, msg): cmds["tanken"] = tanken -#TODO def fuck(sender, args, msg): if not sender in num2name: send("ERROR: you must register first") @@ -359,13 +385,19 @@ def fuck(sender, args, msg): output = name + ": sorry I fucked up!\nRewinding:\n" output += ' '.join(args) + "\n" for change in last_changes: - output += "{} {} {} {}\n".format(change[0], - ("->" if change[2] < 0 else "<-"), - to_euro(abs(change[2])), - change[1]) - record(change[1], change[0], change[2]) + if not change[0] in cmds: + output += "{} {} {} {}\n".format(change[0], + ("->" if change[2] < 0 else "<-"), + to_euro(abs(change[2])), + change[1]) + record(change[1], change[0], change[2]) send(output) + + for change in last_changes: + if change[0] in cmds: + cmds[change[0]](sender, change, "") + return 0 cmds["fuck"] = fuck @@ -376,8 +408,9 @@ def schedule(sender, args, msg): if not sender in num2name: send("ERROR: you must register first") return 1 + sender_name = num2name[sender] - if args < 3: + if len(args) < 3: send('ERROR: not in form "{} name cmd"'.format(args[0])) return 1 @@ -401,13 +434,22 @@ def schedule(sender, args, msg): send('ERROR: the command "{}" failed and will not be recorded') return 1 - scheduled_cmd = {"schedule": args[0][0], + scheduled_cmd = {"schedule": args[0][1:], "last_time": None, "sender": sender, "cmd": cmd} scheduled_cmds[name] = scheduled_cmd - send('Recorded the {} command "{}" as {}'.format(args[0], cmd, name)) + send('Recorded the {} command "{}" as "{}"\n'.format(args[0][1:], ' '.join(cmd), name)) + + send("Running {} command {} for {} initially\n".format(scheduled_cmd["schedule"], + name, sender_name)) + + cmds[cmd[0]](sender, cmd, "") + changes[sender_name][0].append(["cancel", name]) + + now = datetime.now().date() + scheduled_cmd["last_time"] = now.isoformat() cmds["weekly"] = schedule cmds["monthly"] = schedule @@ -420,14 +462,16 @@ def cancel(sender, args, msg): return 1 cmd = scheduled_cmds[cmd_name] - if not cmd.sender == sender: + if not cmd["sender"] == sender: send('ERROR: only the original creator can cancel this command') return 1 del(scheduled_cmds[cmd_name]) - send('Canceled {}'.format(cmd_name)) + send('Cancelled the {} cmd "{}"'.format(cmd["schedule"], cmd_name)) return 0 +cmds["cancel"] = cancel + def main(): if len(sys.argv) > 1 and sys.argv[1] in ["-d", "--dry-run"]: global dry_run @@ -457,27 +501,46 @@ def main(): send('ERROR: unknown cmd. Enter !help for a list of commands.') # Handle scheduled commands - now = datetime.now() - day_delta = timedelta(60 * 60 * 24) - week_delta = day_delta * 7 - year_delta = day_delta * 365 - for name, cmd in scheduled_cmds.items(): - run = False - last_time = datetime.fromtimestamp(cmd.last_time) + global record_changes + record_changes = False - if cmd.schedule == "y": - run = now - last_time > year_delta - elif cmd.schedule == "w": - run = now.month > last_time.month and now.day >= last_time.day + now = datetime.now().date() + week_delta = timedelta(days=7) + year_delta = timedelta(days=365) + for name, cmd in scheduled_cmds.items(): - run = run or last_time.month == 12 and now.year > last_time.year\ - and now.day >= last_time.day + last_time = cmd["last_time"] + if hasattr(date, "fromisoformat"): + last_time = date.fromisoformat(last_time) else: - run = now - last_time > week_delta + last_time = date(*map(int, last_time.split("-"))) + + d = last_time + while True: + if cmd["schedule"] == "yearly": + d = date(d.year+1, d.month, d.day) + elif cmd["schedule"] == "monthly": + if d.day > 28: + d = date(d.year, d.month, 28) + + if d.month == 12: + d = date(d.year+1, 1, d.day) + else: + d = date(d.year, d.month+1, d.day) + else: + d = d + timedelta(7) + + if d <= now: + send("Running {} command {} for {} triggert on {}\n".format(cmd["schedule"], + name, + num2name[cmd["sender"]], + d.isoformat())) + + cmds[cmd["cmd"][0]](cmd["sender"], cmd["cmd"], "") + cmd["last_time"] = d.isoformat() + else: + break - if run: - cmds[cmd.cmd[0]](cmd.sender, cmd.cmd, "") - cmd["last_time"] = now.timestamp() with open(state_file, "w") as f: json.dump(state, f) -- cgit v1.2.3