annotate bnpparibas.py @ 12:4747393db602

Decode messages send time and provide a nicer representation in emails
author Daniele Nicolodi <daniele@grinta.net>
date Mon, 11 Jan 2016 21:15:53 +0100
parents f3d6d73a7184
children 37ce0dc68cad
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
1 import cgi
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
2 import email
3
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
3 import imp
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
4 import itertools
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
5 import json
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
6 import os.path
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
7 import requests
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
8 import smtplib
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
9 import sqlite3
9
Daniele Nicolodi <daniele@grinta.net>
parents: 7
diff changeset
10 import subprocess
Daniele Nicolodi <daniele@grinta.net>
parents: 7
diff changeset
11 import sys
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
12 import textwrap
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
13 import time
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
14
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
15 from contextlib import contextmanager
12
4747393db602 Decode messages send time and provide a nicer representation in emails
Daniele Nicolodi <daniele@grinta.net>
parents: 11
diff changeset
16 from datetime import datetime
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
17 from email.mime.text import MIMEText
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
18 from email.utils import format_datetime, localtime, parseaddr
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
19 from io import BytesIO
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
20 from pprint import pprint
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
21 from urllib.parse import urljoin
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
22
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
23 from html2text import HTML2Text
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
24 from PIL import Image
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
25
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
26
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
27 URL = 'https://mabanque.bnpparibas/'
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
28
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
29 # message template
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
30 MESSAGE = """\
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
31 From: {message.sender:}
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
32 Subject: {message.subject:}
12
4747393db602 Decode messages send time and provide a nicer representation in emails
Daniele Nicolodi <daniele@grinta.net>
parents: 11
diff changeset
33 Date: {message.date:%a, %d %b %Y %H:%M:%S}
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
34
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
35 {message.body:}
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
36 """
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
37
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
38 # transactions table row template
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
39 TRANSACTION = """{xact.id:14d} {xact.date:10s} {xact.description:54s} {xact.amount:+8.2f}"""
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
40
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
41 # transactions table header
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
42 HEADER = """{:14s} {:10s} {:54s} {:>8s}""".format('Id', 'Date', 'Description', 'Amount')
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
43
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
44 # transactions table footer
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
45 FOOTER = """{:14s} {:10s} {:54s} {{balance:8.2f}}""".format('', '', 'BALANCE')
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
46
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
47 # transactions table horizontal separator
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
48 SEP = """-""" * len(HEADER)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
49
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
50
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
51 # GPG encrypted text is ascii and as such does not require encoding
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
52 # but its decrypted form is utf-8 and therefore the charset header
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
53 # must be set accordingly. define an appropriate charset object
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
54 email.charset.add_charset('utf8 7bit', header_enc=email.charset.SHORTEST,
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
55 body_enc=None, output_charset='utf-8')
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
56
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
57
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
58 def loadconf(filename):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
59 module = imp.new_module('conf')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
60 module.__file__ = filename
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
61 with open(filename) as fd:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
62 exec(compile(fd.read(), filename, 'exec'), module.__dict__)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
63 conf = {}
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
64 for key in dir(module):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
65 if key.isupper():
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
66 conf[key] = getattr(module, key)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
67 return conf
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
68
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
69
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
70 def wrap(p, indent):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
71 return textwrap.fill(p, 72, initial_indent=indent, subsequent_indent=indent)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
72
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
73
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
74 def html2text(html):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
75 # the html2text module does an ok job, but it can be improved in
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
76 # the quality of the transformation and in the coding style
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
77 conv = HTML2Text()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
78 conv.ignore_links = True
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
79 conv.ignore_images = True
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
80 conv.ignore_emphasis = True
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
81 return conv.handle(html)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
82
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
83
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
84 class Mailer:
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
85 def __init__(self, host='localhost', port=25, starttls=True, username=None, password=None):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
86 self.host = host
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
87 self.port = port
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
88 self.starttls = starttls
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
89 self.username = username
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
90 self.password = password
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
91
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
92 @contextmanager
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
93 def connect(self):
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
94 smtp = smtplib.SMTP(self.host, self.port)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
95 if self.starttls:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
96 smtp.starttls()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
97 if self.username:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
98 smtp.login(self.username, self.password)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
99 yield smtp
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
100 smtp.quit()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
101
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
102 def send(self, message, fromaddr=None, toaddr=None):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
103 if not fromaddr:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
104 fromaddr = message['From']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
105 if not toaddr:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
106 toaddr = message['To']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
107 with self.connect() as conn:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
108 conn.sendmail(fromaddr, toaddr, str(message))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
109
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
110
3
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
111 class GPG:
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
112 def __init__(self, homedir):
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
113 self.homedir = homedir
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
114
3
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
115 def encrypt(self, message, sender, recipient):
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
116 sender = parseaddr(sender)[1]
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
117 recipient = parseaddr(recipient)[1]
10
636ea715af1e Switch to GnuPG v2
Daniele Nicolodi <daniele@grinta.net>
parents: 9
diff changeset
118 cmd = [ "gpg2", "--homedir", self.homedir, "--sign", "--encrypt",
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
119 "--batch", "--no-options", "--yes", "--armor",
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
120 "--local-user", sender, "--recipient", recipient, ]
3
1311f6533978 Load configuration from file specified on the command line
Daniele Nicolodi <daniele@grinta.net>
parents: 2
diff changeset
121 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
5
Daniele Nicolodi <daniele@grinta.net>
parents: 4
diff changeset
122 encdata, err = p.communicate(input=message.encode('utf-8'))
4
b4c2db70bbf2 Detect and report gpg invocations errors
Daniele Nicolodi <daniele@grinta.net>
parents: 3
diff changeset
123 if p.returncode:
b4c2db70bbf2 Detect and report gpg invocations errors
Daniele Nicolodi <daniele@grinta.net>
parents: 3
diff changeset
124 raise RuntimeError(p.returncode, err)
5
Daniele Nicolodi <daniele@grinta.net>
parents: 4
diff changeset
125 return encdata.decode('ascii')
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
126
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
127
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
128 class Transaction:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
129 __slots__ = 'id', 'date', 'category', 'description', 'amount', 'currency'
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
130
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
131 def __init__(self, id, date, category, description, amount, currency):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
132 self.id = id
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
133 self.date = date
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
134 self.category = category
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
135 self.description = description
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
136 self.amount = amount
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
137 self.currency = currency
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
138
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
139 @classmethod
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
140 def fromjson(cls, x):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
141 data = {'id': int(x['idOperation']),
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
142 'date': x['dateOperation'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
143 'category': int(x['idCategorie']),
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
144 'description': x['libelleOperation'].strip().replace('VIREMENT', 'VIR'),
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
145 'amount': x['montant']['montant'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
146 'currency': x['montant']['currency'], }
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
147 return cls(**data)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
148
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
149 def __str__(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
150 return TRANSACTION.format(xact=self)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
151
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
152
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
153 class Message:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
154 __slots__ = 'id', 'date', 'subject', 'sender', 'content', 'quoted'
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
155
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
156 def __init__(self, id, date, subject, sender, content, quoted):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
157 self.id = id
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
158 self.date = date
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
159 self.subject = subject
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
160 self.sender = sender
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
161 self.content = content
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
162 self.quoted = quoted
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
163
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
164 @classmethod
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
165 def fromjson(cls, x):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
166 data = {'id': x['msg']['id'],
12
4747393db602 Decode messages send time and provide a nicer representation in emails
Daniele Nicolodi <daniele@grinta.net>
parents: 11
diff changeset
167 'date': datetime.strptime(x['msg']['id'], '%Y-%m-%d-%H.%M.%S.%f'),
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
168 'subject': x['msg']['objet'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
169 'sender': x['msg']['emetteur']['nom'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
170 'content': x['msg']['contenu'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
171 'quoted': None, }
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
172 quoted = x.get('msgAttache')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
173 if quoted:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
174 data['quoted'] = quoted['contenu']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
175 return cls(**data)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
176
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
177 @staticmethod
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
178 def normalize(txt, indent=''):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
179 if '<div' in txt:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
180 txt = txt.replace('<br></br>','<br/><br/>')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
181 return html2text(txt)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
182
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
183 txt = txt.replace(r'<br/>', '\n')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
184 parts = []
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
185 for p in txt.split('\n'):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
186 p = p.strip()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
187 if p:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
188 p = wrap(p, indent)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
189 else:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
190 p = indent
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
191 parts.append(p)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
192 return '\n'.join(parts)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
193
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
194 @property
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
195 def body(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
196 body = self.normalize(self.content)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
197 if self.quoted is not None:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
198 body = body + '\n\n' + self.normalize(self.quoted, '> ')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
199 return body
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
200
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
201 def __str__(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
202 return MESSAGE.format(message=self)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
203
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
204
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
205 class Keypad:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
206 def __init__(self, data):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
207 # reference keypad
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
208 fname = os.path.join(os.path.dirname(__file__), 'keypad.jpeg')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
209 reference = Image.open(fname).convert('L')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
210 symbols = [ 8, 4, 1, 6, 3, 7, 9, 0, 5, 2 ]
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
211 self.keypad = dict(zip(symbols, self.imslice(reference)))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
212
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
213 # decode keypad
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
214 image = Image.open(BytesIO(data)).convert('L')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
215 self.keymap = {}
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
216 for n, tile in enumerate(self.imslice(image), 1):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
217 # compare to reference tiles
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
218 for sym, key in self.keypad.items():
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
219 if tile == key:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
220 self.keymap[sym] = n
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
221 break
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
222
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
223 # verify
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
224 if sorted(self.keymap.keys()) != list(range(10)):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
225 raise ValueError('keypad decode failed')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
226
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
227 @staticmethod
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
228 def imslice(image):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
229 for j, i in itertools.product(range(2), range(5)):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
230 yield image.crop((83 * i, 80 * j, 83 * (i + 1), 80 * (j + 1)))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
231
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
232 def encode(self, passwd):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
233 return ''.join('%02d' % self.keymap[d] for d in map(int, passwd))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
234
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
235
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
236 class BNPParibas:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
237 def __init__(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
238 self.session = requests.Session()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
239 self.session.headers.update({'X-Requested-With': 'XMLHttpRequest'})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
240
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
241 @staticmethod
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
242 def validate(response):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
243 response.raise_for_status()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
244 ctype, params = cgi.parse_header(response.headers.get('content-type'))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
245 if ctype == 'application/json':
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
246 data = response.json()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
247 # the status code may sometime be represented as string not int
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
248 code = data.get('codeRetour', -1)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
249 if int(code) != 0:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
250 raise requests.HTTPError()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
251 return data
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
252
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
253 def login(self, username, password):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
254 url = urljoin(URL, 'identification-wspl-pres/identification')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
255 r = self.session.get(url, params={'timestamp': int(time.time())})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
256 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
257
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
258 keypadid = v['data']['grille']['idGrille']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
259 authtemplate = v['data']['authTemplate']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
260
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
261 url = urljoin(URL, 'identification-wspl-pres/grille/' + keypadid)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
262 r = self.session.get(url)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
263 r.raise_for_status()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
264
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
265 keypad = Keypad(r.content)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
266
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
267 # fill authentication template
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
268 auth = authtemplate
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
269 auth = auth.replace('{{ idTelematique }}', username)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
270 auth = auth.replace('{{ password }}', keypad.encode(password))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
271 auth = auth.replace('{{ clientele }}', '')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
272
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
273 url = urljoin(URL, 'SEEA-pa01/devServer/seeaserver')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
274 r = self.session.post(url, data={'AUTH': auth})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
275 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
276 return v['data']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
277
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
278 def info(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
279 url = urljoin(URL, 'serviceinfosclient-wspl/rpc/InfosClient')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
280 r = self.session.get(url, params={'modeAppel': 0})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
281 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
282 return v['data']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
283
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
284 def recent(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
285 url = urljoin(URL, 'udc-wspl/rest/getlstcpt')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
286 r = self.session.get(url)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
287 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
288 account = v['data']['infoUdc']['familleCompte'][0]['compte'][0]
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
289
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
290 url = urljoin(URL, 'rop-wspl/rest/releveOp')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
291 data = json.dumps({'ibanCrypte': account['key'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
292 'pastOrPending': 1, 'triAV': 0,
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
293 'startDate': None, # ddmmyyyy
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
294 'endDate': None})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
295 headers = {'Content-Type': 'application/json'}
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
296 r = self.session.post(url, headers=headers, data=data)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
297 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
298 return v['data']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
299
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
300 def messages(self):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
301 url = urljoin(URL, 'bmm-wspl/recupMsgRecu')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
302 r = self.session.get(url, params={'nbMessagesParPage': 200, 'index': 0})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
303 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
304 return v['data']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
305
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
306 def message(self, mid):
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
307 # required to set some cookies required by the next call
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
308 url = urljoin(URL, 'fr/connexion/mes-outils/messagerie')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
309 r = self.session.get(url)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
310 self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
311
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
312 url = urljoin(URL, 'bmm-wspl/recupMsg')
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
313 r = self.session.get(url, params={'identifiant': mid})
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
314 v = self.validate(r)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
315 return v['data']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
316
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
317
9
Daniele Nicolodi <daniele@grinta.net>
parents: 7
diff changeset
318 def main():
Daniele Nicolodi <daniele@grinta.net>
parents: 7
diff changeset
319 conffile = sys.argv[1]
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
320 conf = loadconf(conffile)
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
321
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
322 db = sqlite3.connect(conf['DATABASE'])
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
323 db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
324 db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
325
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
326 sendmail = Mailer(host=conf['SMTPHOST'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
327 port=conf['SMTPPORT'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
328 starttls=conf['SMTPSTARTTLS'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
329 username=conf['SMTPUSER'],
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
330 password=conf['SMTPPASSWD']).send
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
331
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
332 encrypt = GPG(conf['GNUPGHOME']).encrypt
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
333
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
334 remote = BNPParibas()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
335 remote.login(conf['USERNAME'], conf['PASSWORD'])
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
336
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
337 ## transactions
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
338 recent = remote.recent()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
339 data = recent['listerOperations']['compte']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
340 transactions = [ Transaction.fromjson(x) for x in data['operationPassee'] ]
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
341 balance = data['soldeDispo']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
342
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
343 curs = db.cursor()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
344 unseen = []
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
345 for t in transactions:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
346 curs.execute('''SELECT COUNT(*) FROM transactions WHERE id = ?''', (t.id, ))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
347 if not curs.fetchone()[0]:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
348 # not seen before
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
349 unseen.append(t)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
350
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
351 if unseen:
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
352 lines = []
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
353 lines.append(HEADER)
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
354 lines.append(SEP)
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
355 for t in unseen:
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
356 lines.append(str(t))
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
357 lines.append(SEP)
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
358 lines.append(FOOTER.format(balance=balance))
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
359
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
360 text = '\n'.join(lines)
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
361 payload = encrypt(text, conf['MAILFROM'], conf['MAILTO'])
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
362
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
363 message = MIMEText(payload, _charset='utf8 7bit')
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
364 message['Subject'] = 'BNP Paribas Account update'
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
365 message['From'] = conf['MAILFROM']
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
366 message['To'] = conf['MAILTO']
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
367 message['Date'] = format_datetime(localtime())
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
368
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
369 sendmail(message)
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
370
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
371 curs.executemany('''INSERT INTO transactions (id) VALUES (?)''', ((x.id, ) for x in unseen))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
372 db.commit()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
373
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
374 ## messages
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
375 data = remote.info()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
376 info = data['abonnement']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
377 nnew = info['nombreMessageBMMNonLus'] + info['nombreMessageBilatNonLus']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
378
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
379 data = remote.messages()
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
380 for m in data['messages']:
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
381
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
382 curs = db.cursor()
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
383 curs.execute('''SELECT COUNT(*) FROM messages WHERE id = ?''', (m['id'], ))
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
384 if curs.fetchone()[0]:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
385 # already handled
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
386 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
387
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
388 text = Message.fromjson(remote.message(m['id']))
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
389 payload = encrypt(str(text), conf['MAILFROM'], conf['MAILTO'])
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
390
11
Daniele Nicolodi <daniele@grinta.net>
parents: 10
diff changeset
391 message = MIMEText(payload, _charset='utf8 7bit')
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
392 message['Subject'] = 'BNP Paribas Message'
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
393 message['From'] = conf['MAILFROM']
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
394 message['To'] = conf['MAILTO']
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
395 message['Date'] = format_datetime(localtime())
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
396
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
397 sendmail(message)
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
398
7
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
399 curs.execute('''INSERT INTO messages (id) VALUES (?)''', (m['id'], ))
90f4e0bd0c2d Almost complete rewrite to adapt to the new BNP Paribas website
Daniele Nicolodi <daniele@grinta.net>
parents: 6
diff changeset
400 db.commit()
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
401
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
402
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
403 if __name__ == '__main__':
9
Daniele Nicolodi <daniele@grinta.net>
parents: 7
diff changeset
404 main()