Commit | Line | Data |
---|---|---|
be69f65b | 1 | import os, pwd, hashlib, pickle |
717d54fc FT |
2 | |
3 | def _localname(type): | |
4 | mod = type.__module__ | |
5 | if mod.startswith("fulbank."): | |
6 | mod = mod[8:] | |
7 | return "%s.%s" % (mod, type.__name__) | |
8 | ||
9 | class account(object): | |
10 | @property | |
11 | def number(self): raise NotImplementedError("account.number") | |
12 | @property | |
13 | def name(self): raise NotImplementedError("account.name") | |
14 | def transactions(self): raise NotImplementedError("account.transactions") | |
15 | ||
16 | def __repr__(self): | |
17 | return "#<%s %s: %r>" % (_localname(type(self)), self.number, self.name) | |
18 | ||
19 | class txnaccount(account): | |
20 | @property | |
21 | def balance(self): raise NotImplementedError("txnaccount.balance") | |
22 | @property | |
23 | def clearing(self): raise NotImplementedError("txnaccount.clearing") | |
24 | @property | |
25 | def fullnumber(self): raise NotImplementedError("txnaccount.fullnumber") | |
26 | ||
27 | class cardaccount(account): | |
28 | pass | |
29 | ||
30 | class transaction(object): | |
31 | @property | |
32 | def value(self): raise NotImplementedError("transaction.value") | |
33 | @property | |
34 | def message(self): raise NotImplementedError("transaction.message") | |
35 | @property | |
36 | def date(self): raise NotImplementedError("transaction.date") | |
37 | ||
38 | @property | |
39 | def hash(self): | |
40 | dig = hashlib.sha256() | |
41 | dig.update(str(self.date.toordinal()).encode("ascii") + b"\0") | |
42 | dig.update(self.message.encode("utf-8") + b"\0") | |
43 | dig.update(str(self.value.amount).encode("ascii") + b"\0") | |
44 | dig.update(self.value.currency.symbol.encode("ascii") + b"\0") | |
45 | return dig.hexdigest() | |
46 | ||
47 | def __repr__(self): | |
48 | return "#<%s %s: %r>" % (_localname(type(self)), self.value, self.message) | |
be69f65b FT |
49 | |
50 | class session(object): | |
51 | def save(self, filename): | |
52 | with open(filename, "wb") as fp: | |
53 | pickle.dump(self, fp) | |
54 | ||
55 | @staticmethod | |
56 | def load(filename): | |
57 | with open(filename, "rb") as fp: | |
58 | return pickle.load(fp) | |
59 | ||
60 | def getsessnam(name): | |
61 | if name == "fsb": | |
62 | from . import fsb | |
63 | return fsb.session | |
64 | raise ValueError("no such known session type: " + name) | |
65 | ||
66 | def _sesspath(name): | |
67 | return os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".cache/fulbank", name) | |
68 | ||
69 | def defaultsess(): | |
70 | ret = os.getenv("NETBANKSESS") | |
71 | if ret: | |
72 | return ret | |
73 | return "master" | |
74 | ||
75 | def loadsess(name=None, default=FileNotFoundError): | |
76 | if name is None: name = defaultsess() | |
77 | path = _sesspath(name) | |
78 | if not os.path.exists(path): | |
79 | if default is FileNotFoundError: | |
80 | raise FileNotFoundError(name) | |
81 | return default | |
82 | return session.load(path) | |
83 | ||
84 | def savesess(sess, name=None): | |
85 | if name is None: name = defaultsess() | |
86 | path = _sesspath(name) | |
87 | if sess is not None: | |
88 | sessdir = os.path.dirname(path) | |
89 | if not os.path.isdir(sessdir): | |
90 | os.makedirs(sessdir) | |
91 | return sess.save(_sesspath(name)) | |
92 | else: | |
93 | if os.path.exists(path): | |
94 | os.unlink(path) | |
95 | ||
96 | class savedsess(object): | |
97 | def __init__(self, name=None): | |
98 | if name is None: name = defaultsess() | |
99 | self.name = name | |
100 | self.sess = None | |
101 | ||
102 | def __enter__(self): | |
103 | self.sess = loadsess(self.name) | |
104 | return self.sess | |
105 | ||
106 | def __exit__(self): | |
107 | savesess(self.sess, name) | |
108 | self.sess = None |