def test_api_context_restore(self): """ Saves an ApiContext to a temporary file, restores an ApiContext from that file, and compares whether the api_keys, tokens, and environment types are equal in the ApiContext and the restored ApiContext. Removes the temporary file before assertion. """ self._API_CONTEXT.save(self._TMP_FILE_PATH_FULL) api_context_restored = ApiContext.restore(self._TMP_FILE_PATH_FULL) os.remove(self._TMP_FILE_PATH_FULL) self.assertEqual(api_context_restored, self._API_CONTEXT)
def setup_context(self): if isfile(self.determine_bunq_conf_filename()): pass # Config is already present elif self.env == ApiEnvironmentType.SANDBOX: sandbox_user = self.generate_new_sandbox_user() ApiContext(ApiEnvironmentType.SANDBOX, sandbox_user.api_key, socket.gethostname()).save( self.determine_bunq_conf_filename()) else: raise BunqException(self._ERROR_COULD_NOT_DETIRMINE_CONF) api_context = ApiContext.restore(self.determine_bunq_conf_filename()) api_context.ensure_session_active() api_context.save(self.determine_bunq_conf_filename()) BunqContext.load_api_context(api_context)
def setup_context(self): if Path(self.determine_bunq_conf_filename()).is_file(): pass else: sandbox_user = self.generate_new_sandbox_user() ApiContext( ApiEnvironmentType.SANDBOX, sandbox_user.api_key, socket.gethostname() ).save(self.determine_bunq_conf_filename()) self._api_context = ApiContext.restore(self.determine_bunq_conf_filename()) self._api_context.ensure_session_active() self._api_context.save(self.determine_bunq_conf_filename()) BunqContext.load_api_context(self._api_context) self._user_context = BunqContext.user_context()
def setup_context(self, reset_config_if_needed=True): if isfile(self.determine_bunq_conf_filename()): pass # Config is already present elif self.env == ApiEnvironmentType.SANDBOX: sandbox_user = self.generate_new_sandbox_user() ApiContext(ApiEnvironmentType.SANDBOX, sandbox_user.api_key, socket.gethostname()).save( self.determine_bunq_conf_filename()) else: raise BunqException(self._ERROR_COULD_NOT_DETERMINE_CONF) try: api_context = ApiContext.restore( self.determine_bunq_conf_filename()) api_context.ensure_session_active() api_context.save(self.determine_bunq_conf_filename()) BunqContext.load_api_context(api_context) except ForbiddenException as forbidden_exception: if reset_config_if_needed: self.__handle_forbidden_exception(forbidden_exception) else: raise forbidden_exception
from bunq.sdk.client import Pagination from bunq.sdk.context import ApiContext from bunq.sdk.context import ApiEnvironmentType from bunq.sdk.context import BunqContext from bunq.sdk.model.generated import endpoint from json import dumps if "SECRET" not in environ: print("SECRET not specified. Exiting.") exit(0) app = Flask(__name__) CONTEXT_FILE = "bunq-production.conf" api_context = ApiContext.restore(CONTEXT_FILE) api_context.ensure_session_active() api_context.save(CONTEXT_FILE) BunqContext.load_api_context(api_context) def get_all_monetary_account_active(): pagination = Pagination() pagination.count = 25 all_monetary_account_bank = endpoint.MonetaryAccountBank.list(pagination.url_params_count_only).value all_monetary_account_bank_active = [] for monetary_account_bank in all_monetary_account_bank: if monetary_account_bank.status == "ACTIVE": all_monetary_account_bank_active.append(monetary_account_bank)
def all_transactions(dt=None): # This should be enough to ensure the whole account is included. if dt == None: dt = epoch env = ApiEnvironmentType.PRODUCTION if not isfile('bunq-production.conf'): raise Exception("No config file found, run start.py first.") # Reload the API context api_context = ApiContext.restore('bunq-production.conf') api_context.ensure_session_active() api_context.save('bunq-production.conf') BunqContext.load_api_context(api_context) # User info user = endpoint.User.get().value.get_referenced_object() # To get a list we want a pagination object. # When making a pagination object yourself you normally only set the 'count' # Then you get the url params from it using 'url_params_count_only' pagination = Pagination() pagination.count = 100 accounts = [] all_monetary_account_bank = endpoint.MonetaryAccountBank.list( pagination.url_params_count_only).value for monetary_account_bank in all_monetary_account_bank: if monetary_account_bank.status == "ACTIVE": accounts.append(monetary_account_bank) all_monetary_account_savings = endpoint.MonetaryAccountSavings.list( pagination.url_params_count_only).value for monetary_account_savings in all_monetary_account_savings: if monetary_account_savings.status == "ACTIVE": accounts.append(monetary_account_savings) # Reload where we where last time. try: with open("seen.pickle", "rb") as fp: seen = pickle.load(fp) except Exception: seen = set() # We will keep a list of transactions that are already processed in this set. # The transactions will contain: # - A set of the two possible roundings of the datestamp # - The ammount of money in absolute value # - The description # - A set containing the two accounts involved # The goal here is that this representation is the same for two accounts when shifting money arround. for a in accounts: aid = a.id_ # keep track of where we are print(a.description) for p in iter_payments(aid): # python can handle the dates we get back date = dateparse.parse(p.created) #round to the second to get a (sort of) unique, but not to precise timestamp since_epoch = int(unix_time(date)) row = [ p.created, p.amount.value, p.description.replace("\r", "").replace("\n", " "), p.alias.label_monetary_account.iban, p.counterparty_alias.label_monetary_account.iban ] # frozenset can be used to hash a set, so the order does not matter. summary = ( unique_float( since_epoch), #take both so there is norounding problem abs(float(p.amount.value)), p.description, frozenset([ p.alias.label_monetary_account.iban, p.counterparty_alias.label_monetary_account.iban ])) # Still in range if date >= dt: if summary in seen: continue else: seen.add(summary) yield (row) else: break with open("seen.pickle", "wb") as fp: pickle.dump(seen, fp)
from os.path import isfile import argparse from bunq.sdk.context import ApiContext from bunq.sdk.context import ApiEnvironmentType parser = argparse.ArgumentParser("Generate a Bunq API context.") parser.add_argument("api_key", metavar="KEY", help="An API key as acquired from the Bunq app.") parser.add_argument("device_name", metavar="NAME", help="A device name.") parser.add_argument("output_filename", metavar="FILE", help="A destination for the context.") args = parser.parse_args() ApiContext(ApiEnvironmentType.PRODUCTION, args.api_key, args.device_name).save(args.output_filename) api_context = ApiContext.restore(args.output_filename) api_context.ensure_session_active() api_context.save()