summaryrefslogtreecommitdiff
path: root/email_assistant/plugins/delta.py
diff options
context:
space:
mode:
authorJames E. Blair <corvus@gnu.org>2019-06-09 10:05:11 -0700
committerJames E. Blair <corvus@gnu.org>2019-06-09 10:07:14 -0700
commit3177ba26421b730bdf475fc2e991eef9ab9ef067 (patch)
treea7cce1756ccb5d6c50b1b56e1b24885ba683851f /email_assistant/plugins/delta.py
parentc44874cfa48bf00b83057033fc7800b35e157702 (diff)
Add support for Delta
Also add an undocumented mailbox driver for a directory of files for ease of testing (this could probably become a maildir driver with a bit more work). Remove unecessary decode calls from the message traversal.
Diffstat (limited to 'email_assistant/plugins/delta.py')
-rw-r--r--email_assistant/plugins/delta.py115
1 files changed, 115 insertions, 0 deletions
diff --git a/email_assistant/plugins/delta.py b/email_assistant/plugins/delta.py
new file mode 100644
index 0000000..50da506
--- /dev/null
+++ b/email_assistant/plugins/delta.py
@@ -0,0 +1,115 @@
1#!/usr/bin/env python3
2
3# Copyright (C) 2019 James E. Blair <corvus@gnu.org>
4#
5# This file is part of Email-assistant.
6#
7# Email-assistant is free software: you can redistribute it and/or
8# modify it under the terms of the GNU Affero General Public License
9# as published by the Free Software Foundation, either version 3 of
10# the License, or (at your option) any later version.
11#
12# Email-assistant is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Email-assistant. If not, see
19# <https://www.gnu.org/licenses/>.
20
21import re
22import logging
23import hashlib
24
25from bs4 import BeautifulSoup
26import dateutil.parser
27import dateutil.tz
28import inscriptis
29import vobject
30
31from email_assistant import iata
32from email_assistant import plugin
33
34def parse_dep_arr(dep_date, flight_date, flight_time, code):
35 flight_year = dep_date.year
36 tz = iata.tzmap[code]
37 flight_time = dateutil.parser.parse(flight_date + ' ' + flight_time)
38 if flight_time.year < flight_year:
39 flight_time.replace(year=flight_year)
40 flight_time = flight_time.replace(tzinfo=dateutil.tz.gettz(tz))
41 return flight_time
42
43class Plugin(plugin.Plugin):
44 name = 'delta'
45
46 def match(self, msg):
47 if ('DeltaAirLines@e.delta.com' in msg['From'] and
48 'Your Flight Receipt' in msg['Subject']):
49 return True
50
51 def get_events(self, msg):
52 events = []
53 for part in msg.walk():
54 if part.get_content_type() == 'text/html':
55 soup = BeautifulSoup(part.get_payload(decode=True), 'html.parser')
56 flights = []
57 flight = None
58 dep_date = None
59 start = soup.find(string=re.compile('FLIGHT INFO STARTS'))
60 for row in start.parent.find_all('tr', recursive=False):
61 row = [x.strip() for x in row.strings if x.strip()]
62 if len(row) == 3 and row[1:] == ['DEPART', 'ARRIVE']:
63 dep_date = row[0]
64 continue
65 if dep_date is None: continue
66 f = {
67 'dep_date': dep_date,
68 #'num': row[0],
69 #'cabin': row[1],
70 'dep_city': row[2],
71 'dep_time': row[3],
72 'arr_city': row[4],
73 'arr_time': row[5]}
74 if len(row) > 6:
75 f['arr_date'] = row[6].replace('*', '').strip()
76 else:
77 f['arr_date'] = dep_date
78 flights.append(f)
79 start = soup.find(string=re.compile('Checked Bag Allowance'))
80 while start.name != 'table': start = start.parent
81 start = start.parent
82 while start.name != 'table': start = start.parent
83 index = 0
84 for row in start.find_all('tr', recursive=False):
85 row = [x.strip() for x in row.strings if x.strip()]
86 if len(row) != 3: continue
87 try:
88 dep_date = dateutil.parser.parse(row[0])
89 except Exception:
90 continue
91 f = flights[index]
92 f['dep_code'] = row[1].split()[-1].strip()
93 f['arr_code'] = row[2].split()[-1].strip()
94 f['dep_dt'] = parse_dep_arr(
95 dep_date, f['dep_date'], f['dep_time'], f['dep_code'])
96 f['arr_dt'] = parse_dep_arr(
97 dep_date, f['arr_date'], f['arr_time'], f['arr_code'])
98 index += 1
99 for f in flights:
100 self.log.debug('%s %s %s %s',
101 f['dep_dt'], f['arr_dt'], f['dep_code'], f['arr_code'])
102 cal = vobject.iCalendar()
103 event = cal.add('vevent')
104 event.add('dtstart').value = f['dep_dt']
105 event.add('dtend').value = f['arr_dt']
106 summary = "Flight from %s to %s" % (f['dep_code'], f['arr_code'])
107 event.add('summary').value = summary
108 text = inscriptis.get_text(str(soup))
109 text = re.sub(r'([^ ]+)\s*\n', '\\1\n', text)
110 event.add('description').value = text
111 event.add('location').value = "%s airport" % (f['dep_code'],)
112 uid = hashlib.sha1((str(f['dep_time']) + summary).encode('utf8')).hexdigest()
113 event.add('uid').value = uid
114 events.append(cal)
115 return events