From f85342dc2ec07cd9f2892893073be96fe6fe797c Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 9 Apr 2022 20:18:23 +0100 Subject: [PATCH] Implement removing accounts from Nordigen --- handler/lib/serde/nordigen.py | 5 ++++ handler/sinks/nordigen.py | 44 ++++++++++++++++++++++++++++++++++- handler/ux/commands.py | 40 ++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/handler/lib/serde/nordigen.py b/handler/lib/serde/nordigen.py index 7f4ec04..b90e5aa 100644 --- a/handler/lib/serde/nordigen.py +++ b/handler/lib/serde/nordigen.py @@ -97,3 +97,8 @@ class AccountBalances(Model): class AccountBalancesRoot(Model): balances = fields.List(AccountBalances) + + +class RequisitionResponse(Model): + summary: fields.Str() + detail: fields.Str() diff --git a/handler/sinks/nordigen.py b/handler/sinks/nordigen.py index dcdfed6..76aab6f 100644 --- a/handler/sinks/nordigen.py +++ b/handler/sinks/nordigen.py @@ -5,7 +5,16 @@ from twisted.internet.task import LoopingCall import requests from simplejson.errors import JSONDecodeError from json import dumps, loads -from lib.serde.nordigen import TXRoot, AccessToken, Institutions, Agreement, Requisitions, AccountDetails, AccountBalancesRoot +from lib.serde.nordigen import ( + TXRoot, + AccessToken, + Institutions, + Agreement, + Requisitions, + AccountDetails, + AccountBalancesRoot, + RequisitionResponse, +) from serde import ValidationError # Project imports @@ -163,6 +172,21 @@ class Nordigen(util.Base): return False + def delete_requisition(self, requisition_id): + """ + Delete a requisision ID. + """ + headers = {"accept": "application/json", "Authorization": f"Bearer {self.token}"} + path = f"{settings.Nordigen.Base}/requisitions/{requisition_id}/" + r = requests.delete(path, headers=headers) + try: + obj = RequisitionResponse.from_json(r.content) + except ValidationError as err: + self.log.error(f"Validation error: {err}") + return + parsed = obj.to_dict() + return parsed + def get_accounts(self, requisition): """ Get a list of accounts for a requisition. @@ -231,6 +255,24 @@ class Nordigen(util.Base): return currency + def unmap_account(self, account_id): + """ + Unmap an account_id at a bank to an account_name. + This disables the account for fetching. + Data type: {"monzo": [account, ids, here], + "revolut": [account, ids, here]} + """ + + existing_entry = loads(settings.Nordigen.Maps) + if account_id not in existing_entry: + return + else: + existing_entry.remove(account_id) + + settings.Nordigen.Maps = dumps(existing_entry) + self.banks = existing_entry + settings.write() + def get_all_account_info(self): to_return = {} requisitions = self.get_requisitions() diff --git a/handler/ux/commands.py b/handler/ux/commands.py index ea97760..29080de 100644 --- a/handler/ux/commands.py +++ b/handler/ux/commands.py @@ -586,6 +586,32 @@ class IRCCommands(object): reference = transaction["reference"] msg(f"{timestamp} {txid} {amount}{currency} {reference}") + class nreqs(object): + name = "nreqs" + authed = True + helptext = "Get a list of requisitions from Nordigen." + + @staticmethod + def run(cmd, spl, length, authed, msg, agora, tx, ux): + reqs = tx.sinks.nordigen.get_requisitions() + for req in reqs: + id = req["id"] + institution_id = req["institution_id"] + redirect = req["link"] + msg(f"{id} {institution_id} {redirect}") + + class ndelreq(object): + name = "ndelreq" + authed = True + helptext = "Delete a requisition from Nordigen." + + @staticmethod + def run(cmd, spl, length, authed, msg, agora, tx, ux): + if length == 2: + requisition_id = spl[1] + rtrn = tx.sinks.nordigen.delete_requisition(requisition_id) + msg(f"{rtrn['summary']}") + class mapaccount(object): name = "mapaccount" authed = True @@ -605,7 +631,7 @@ class IRCCommands(object): class nmapaccount(object): name = "nmapaccount" authed = True - helptext = "Enable an account_id at a bank for use in Nordigen. Usage: nmapaccount " + helptext = "Enable an account_id at a bank for use in Nordigen. Usage: nmapaccount " @staticmethod def run(cmd, spl, length, authed, msg, agora, tx, ux): @@ -617,6 +643,18 @@ class IRCCommands(object): return msg(f"Mapped account ID {account_id} to {account_name}") + class nunmapaccount(object): + name = "nunmapaccount" + authed = True + helptext = "Disable an account_id at a bank for use in Nordigen. Usage: nunmapaccount " + + @staticmethod + def run(cmd, spl, length, authed, msg, agora, tx, ux): + if length == 2: + account_id = spl[1] + tx.sinks.nordigen.unmap_account(account_id) + msg(f"Unmapped account ID {account_id}") + class unmapped(object): name = "unmapped" authed = True