0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
1 import email
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
2 import os.path
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
3 import re
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
4 import smtplib
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
5 import sqlite3
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
6 import subprocess
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
7 import textwrap
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
8
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
9 from collections import namedtuple, defaultdict
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
10 from contextlib import contextmanager
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
11 from datetime import datetime
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
12 from decimal import Decimal
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
13 from email.mime.text import MIMEText
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
14 from email.utils import format_datetime, localtime, parseaddr
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
15 from io import BytesIO
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
16 from itertools import product, islice
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
17 from urllib.parse import urljoin
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
18
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
19 import bs4
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
20 import requests
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
21
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
22 from PIL import Image
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
23
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
24 DB = 'bnpparibas.sqlite'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
25
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
26 # message template
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
27 MESSAGE = """\
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
28 From: {sender:}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
29 Subject: {subject:}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
30 Date: {date:}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
31 Message-Id: {id:}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
32
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
33 {body:}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
34 """
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
35
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
36 # transaction template
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
37 HEADER = '{:14s} {:10s} {:59s} {:>8s}'.format('Id', 'Date', 'Description', 'Amount')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
38 TRANSACTION = '{id:} {date:%d/%m/%Y} {descr:59s} {amount:>8s}'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
39
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
40 # as defined in bnpbaribas web app
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
41 CATEGORIES = {
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
42 '1': 'Alimentation',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
43 '7': 'Logement',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
44 '8': 'Loisirs',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
45 '9': 'Transport',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
46 '12': 'Opérations bancaires',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
47 '13': 'Non défini',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
48 '14': 'Multimédia',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
49 '20': 'Energies',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
50 '22': 'Retrait',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
51 '23': 'Sorties',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
52 'R58': 'Non défini',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
53 }
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
54
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
55 # euro symbol
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
56 EURO = b'\xe2\x82\xac'.decode('utf-8')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
57
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
58
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
59 # load configuration
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
60 from config import *
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
61
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
62
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
63 # GPG encrypted text is ascii and as such does not require encoding
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
64 # but its decrypted form is utf-8 and therefore the charset header
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
65 # must be set accordingly. define an appropriate charset object
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
66 email.charset.add_charset('utf8 7bit', header_enc=email.charset.SHORTEST,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
67 body_enc=None, output_charset='utf-8')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
68
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
69
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
70 Message = namedtuple('Message', 'id read icon sender subject date validity'.split())
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
71
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
72
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
73 class Transaction:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
74 def __init__(self, tid, date, descr, debit, credit, category):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
75 self.id = tid
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
76 self.date = date
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
77 self.descr = descr
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
78 self.debit = debit
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
79 self.credit = credit
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
80 self.category = category
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
81
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
82 def __str__(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
83 # there does not seem to be an easy way to format Decimal
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
84 # objects with a leading sign in both the positive and
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
85 # negative value cases so do it manually
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
86 d = vars(self)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
87 if d['debit']:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
88 d['amount'] = '-' + str(d['debit'])
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
89 if d['credit']:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
90 d['amount'] = '+' + str(d['credit'])
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
91 return TRANSACTION.format(**d)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
92
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
93
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
94 def imslice(image):
|
2
|
95 for y, x in product(range(0, 5), range(0, 5)):
|
|
96 yield image.crop((27 * x + 1, 27 * y + 1, 27 * (x + 1), 27 * (y + 1)))
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
97
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
98
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
99 def imdecode(image):
|
2
|
100 # load reference keypad
|
|
101 keypad = Image.open(os.path.join(os.path.dirname(__file__), 'keypad.png')).convert('L')
|
|
102 keypad = [ keypad.crop((26 * i, 0, 26 * (i + 1), 26)) for i in range(10) ]
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
103 immap = {}
|
2
|
104 for n, tile in enumerate(imslice(image)):
|
|
105 # skip tiles with background only
|
|
106 if tile.getextrema()[0] > 0:
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
107 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
108 # compare to reference tiles
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
109 for d in range(0, 10):
|
2
|
110 if tile == keypad[d]:
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
111 immap[d] = n + 1
|
2
|
112 break
|
|
113 if sorted(immap.keys()) != list(range(10)):
|
|
114 raise ValueError('keypad decode failed')
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
115 return immap
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
116
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
117
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
118 def amountparse(value):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
119 # empty
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
120 if value == '\xa0':
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
121 return None
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
122 m = re.match(r'\s+((?:\d+\.)?\d+,\d+)\s+([^\s]+)\s+$', value, re.U|re.S)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
123 if m is None:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
124 raise ValueError(repr(value))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
125 # euro
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
126 currency = m.group(2)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
127 if currency != EURO:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
128 raise ValueError(repr(currency))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
129 return Decimal(m.group(1).replace('.', '').replace(',', '.'))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
130
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
131
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
132 class Site:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
133 def __init__(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
134 self.url = 'https://www.secure.bnpparibas.net'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
135 self.req = requests.Session()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
136
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
137 def login(self, user, passwd):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
138 # login page
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
139 url = urljoin(self.url, '/banque/portail/particulier/HomeConnexion')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
140 r = self.req.get(url, params={'type': 'homeconnex'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
141 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
142 # login form
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
143 soup = bs4.BeautifulSoup(r.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
144 form = soup.find('form', attrs={'name': 'logincanalnet'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
145 # extract relevant data
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
146 action = form['action']
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
147 data = { field['name']: field['value'] for field in form('input') }
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
148
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
149 # keyboard image url
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
150 src = ''
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
151 tag = soup.find(attrs={'id': 'secret-nbr-keyboard'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
152 for prop in tag['style'].split(';'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
153 match = re.match(r'background-image:\s+url\(\'(.*)\'\)\s*', prop)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
154 if match:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
155 src = match.group(1)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
156 break
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
157 # download keyboard image
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
158 r = self.req.get(urljoin(self.url, src))
|
2
|
159 image = Image.open(BytesIO(r.content)).convert('L')
|
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
160 # decode digits position
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
161 passwdmap = imdecode(image)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
162
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
163 # encode password
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
164 passwdenc = ''.join('%02d' % passwdmap[d] for d in map(int, passwd))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
165
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
166 # username and password
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
167 data['ch1'] = user
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
168 data['ch5'] = passwdenc
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
169
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
170 # post
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
171 r = self.req.post(urljoin(self.url, action), data=data)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
172 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
173 # redirection
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
174 m = re.search(r'document\.location\.replace\(\"(.+)\"\)', r.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
175 dest = m.group(1)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
176 r = self.req.get(dest)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
177 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
178
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
179 # check for errors
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
180 soup = bs4.BeautifulSoup(r.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
181 err = soup.find(attrs={'class': 'TitreErreur'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
182 if err:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
183 raise ValueError(err.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
184
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
185
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
186 def recent(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
187 data = {
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
188 'BeginDate': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
189 'Categs': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
190 'Contracts': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
191 'EndDate': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
192 'OpTypes': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
193 'cboFlowName': 'flow/iastatement',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
194 'contractId': CONTRACT,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
195 'contractIds': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
196 'entryDashboard': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
197 'execution': 'e6s1',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
198 'externalIAId': 'IAStatements',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
199 'g1Style': 'expand',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
200 'g1Type': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
201 'g2Style': 'collapse',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
202 'g2Type': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
203 'g3Style': 'collapse',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
204 'g3Type': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
205 'g4Style': 'collapse',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
206 'g4Type': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
207 'groupId': '-2',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
208 'groupSelected': '-2',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
209 'gt': 'homepage:basic-theme',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
210 'pageId': 'releveoperations',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
211 'pastOrPendingOperations': '1',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
212 'sendEUD': 'true',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
213 'step': 'STAMENTS', }
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
214
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
215 url = urljoin(self.url, '/banque/portail/particulier/FicheA')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
216 r = self.req.post(url, data=data)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
217 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
218 text = r.text
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
219
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
220 # the html is so broken beautifulsoup does not understand it
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
221 text = text.replace(
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
222 '<th class="thTitre" style="width:7%">Pointage </td>',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
223 '<th class="thTitre" style="width:7%">Pointage </th>')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
224 s = bs4.BeautifulSoup(text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
225
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
226 # extract transactions
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
227 table = s.find('table', id='tableCompte')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
228 rows = table.find_all('tr')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
229 for row in rows:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
230 fields = row.find_all('td')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
231 if not fields:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
232 # skip headers row
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
233 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
234 id = int(fields[0].input['id'].lstrip('_'))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
235 date = datetime.strptime(fields[1].text, '%d/%m/%Y')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
236 descr = fields[2].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
237 debit = amountparse(fields[3].text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
238 credit = amountparse(fields[4].text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
239 category = fields[5].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
240 categoryid = fields[6].span['class'][2][4:]
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
241 yield Transaction(id, date, descr, debit, credit, categoryid)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
242
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
243
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
244 def messages(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
245 data = {
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
246 'identifiant': 'BmmFicheListerMessagesRecus_20100607022434',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
247 'type': 'fiche', }
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
248
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
249 url = urljoin(self.url, '/banque/portail/particulier/Fiche')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
250 r = self.req.post(url, data=data)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
251 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
252 s = bs4.BeautifulSoup(r.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
253
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
254 # messages list
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
255 table = s.find('table', id='listeMessages')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
256 for row in table.find_all('tr', recursive=False):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
257 # skip headers and separators
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
258 if 'entete' in row['class']:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
259 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
260 # skip separators
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
261 if 'sep' in row['class']:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
262 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
263 # skip footer
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
264 if 'actions_bas' in row['class']:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
265 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
266 fields = row.find_all('td')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
267 icon = fields[1].img['src']
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
268 sender = fields[2].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
269 subject = fields[4].a.text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
270 date = datetime.strptime(fields[5]['data'], '%Y/%m/%d:%Hh%Mmin%Ssec')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
271 validity = datetime.strptime(fields[6]['data'], '%Y/%m/%d:%Hh%Mmin%Ssec')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
272 m = re.match(r'''validerFormulaire\('BmmFicheLireMessage_20100607022346','(.+)','(true|false)'\);$''', fields[4].a['onclick'])
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
273 mid = m.group(1)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
274 read = m.group(2) == 'false'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
275 yield Message(mid, read, icon, sender, subject, date, validity)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
276
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
277
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
278 def message(self, mid):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
279 data = {
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
280 'etape': 'boiteReception',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
281 'idMessage': mid,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
282 'identifiant': 'BmmFicheLireMessage_20100607022346',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
283 'maxPagination': 2,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
284 'minPagination': 1,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
285 'nbElementParPage': 20,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
286 'nbEltPagination': 5,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
287 'nbPages': 2,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
288 'newMsg': 'false',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
289 'pagination': 1,
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
290 'type': 'fiche',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
291 'typeAction': '', }
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
292
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
293 url = urljoin(self.url, '/banque/portail/particulier/Fiche')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
294 r = self.req.post(url, data=data)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
295 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
296 # fix badly broken html
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
297 text = r.text.replace('<br>', '<br/>').replace('</br>', '')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
298 s = bs4.BeautifulSoup(text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
299
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
300 envelope = s.find('div', attrs={'class': 'enveloppe'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
301 rows = envelope.find_all('tr')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
302 fields = rows[1].find_all('td')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
303 # the messages list present a truncated sender
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
304 sender = fields[0].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
305 # not used
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
306 subject = fields[1].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
307 date = fields[2].text.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
308
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
309 content = s.find('div', attrs={'class': 'txtMessage'})
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
310 # clean up text
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
311 for t in content.find_all('style'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
312 t.extract()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
313 for t in content.find_all('script'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
314 t.extract()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
315 for t in content.find_all(id='info_pro'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
316 t.extract()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
317 for t in content.find_all('br'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
318 t.replace_with('\n\n')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
319 for t in content.find_all('b'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
320 if t.string:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
321 t.replace_with('*%s*' % t.string.strip())
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
322 for t in content.find_all('li'):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
323 t.replace_with('- %s\n\n' % t.text.strip())
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
324 # format nicely
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
325 text = re.sub(' +', ' ', content.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
326 text = re.sub(r'\s+([\.:])', r'\1', text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
327 pars = []
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
328 for p in re.split('\n\n+', text):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
329 p = p.strip()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
330 if p:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
331 pars.append('\n'.join(textwrap.wrap(p, 72)))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
332 body = '\n\n'.join(pars)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
333 return sender, body
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
334
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
335
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
336 def transactions(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
337 data = {'ch_memo': 'NON',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
338 'ch_rop_cpt_0': 'FR7630004001640000242975804',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
339 'ch_rop_dat': 'tous',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
340 'ch_rop_dat_deb': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
341 'ch_rop_dat_fin': '',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
342 'ch_rop_fmt_dat': 'JJMMAAAA',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
343 'ch_rop_fmt_fic': 'RTEXC',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
344 'ch_rop_fmt_sep': 'PT',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
345 'ch_rop_mon': 'EUR',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
346 'x': '55',
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
347 'y': '7'}
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
348 r = self.req.post(urljoin(self.url, '/SAF_TLC_CNF'), data=data)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
349 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
350 s = bs4.BeautifulSoup(r.text)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
351 path = s.find('a')['href']
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
352 r = self.req.get(urljoin(self.url, path))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
353 r.raise_for_status()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
354 return r.text
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
355
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
356
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
357 class Mailer:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
358 def __init__(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
359 self.server = SMTPSERVER
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
360 self.port = SMTPPORT
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
361 self.starttls = SMTPSTARTTLS
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
362 self.username = SMTPUSER
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
363 self.password = SMTPPASSWD
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
364
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
365 @contextmanager
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
366 def connect(self):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
367 smtp = smtplib.SMTP(self.server, self.port)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
368 if self.starttls:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
369 smtp.starttls()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
370 if self.username:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
371 smtp.login(self.username, self.password)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
372 yield smtp
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
373 smtp.quit()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
374
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
375 def send(self, message, fromaddr=None, toaddr=None):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
376 if not fromaddr:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
377 fromaddr = message['From']
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
378 if not toaddr:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
379 toaddr = message['To']
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
380 with self.connect() as conn:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
381 conn.sendmail(fromaddr, toaddr, str(message))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
382
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
383
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
384 def encrypt(message, sender, recipient):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
385 sender = parseaddr(sender)[1]
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
386 recipient = parseaddr(recipient)[1]
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
387 cmd = [ "gpg", "--homedir", GNUPGHOME, "--batch", "--yes", "--no-options", "--armor",
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
388 "--local-user", sender, "--recipient", recipient, "--sign", "--encrypt"]
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
389 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
390 encdata = p.communicate(input=message.encode('utf-8'))[0].decode('ascii')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
391 return encdata
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
392
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
393
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
394 def main():
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
395 bnp = Site()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
396 bnp.login(USERNAME, PASSWORD)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
397
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
398 db = sqlite3.connect(DB)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
399 db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
400 db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
401
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
402 mailer = Mailer()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
403
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
404 ## unread messages
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
405 messages = filter(lambda x: not x.read, bnp.messages())
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
406 for m in sorted(messages, key=lambda x: x.date):
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
407 curs = db.cursor()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
408 curs.execute('''SELECT IFNULL((SELECT id FROM messages WHERE id = ?), 0)''', (m.id, ))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
409 if curs.fetchone()[0]:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
410 # already handled
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
411 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
412
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
413 # retrieve complete sender and message body
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
414 sender, body = bnp.message(m.id)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
415
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
416 # compose and send message
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
417 body = MESSAGE.format(id=m.id, sender=sender, date=m.date, subject=m.subject, body=body)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
418 message = MIMEText(encrypt(body, MAILFROM, MAILTO), _charset='utf8 7bit')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
419 message['Subject'] = 'BNP Paribas message'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
420 message['From'] = MAILFROM
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
421 message['To'] = MAILTO
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
422 message['Date'] = format_datetime(localtime(m.date))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
423 mailer.send(message)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
424
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
425 curs.execute('''INSERT INTO messages (id) VALUES (?)''', (m.id, ))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
426 db.commit()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
427
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
428
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
429 ## transactions
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
430 transactions = bnp.recent()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
431 curs = db.cursor()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
432 lines = []
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
433 for t in transactions:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
434 curs.execute('''SELECT IFNULL((SELECT id FROM transactions WHERE id = ?), 0)''', (t.id, ))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
435 if curs.fetchone()[0]:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
436 # already handled
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
437 continue
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
438 lines.append(str(t))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
439 curs.execute('''INSERT INTO transactions (id) VALUES (?)''', (t.id, ))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
440
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
441 if lines:
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
442 lines.insert(0, HEADER)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
443 lines.insert(1, '-' * len(HEADER))
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
444 body = '\n'.join(lines)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
445 message = MIMEText(encrypt(body, MAILFROM, MAILTO), _charset='utf8 7bit')
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
446 message['Subject'] = 'BNP Paribas update'
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
447 message['From'] = MAILFROM
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
448 message['To'] = MAILTO
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
449 message['Date'] = format_datetime(localtime())
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
450 mailer.send(message)
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
451
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
452 db.commit()
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
453
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
454
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
455 if __name__ == '__main__':
|
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff
changeset
|
456 main()
|