Skip to content

Commit 01a0bce

Browse files
added handling for dates with triggers; implemented date range queries
1 parent 71ece56 commit 01a0bce

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

calexa.py

+53-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
import re
12
import pprint
23
import json
34
from datetime import datetime
5+
from datetime import timedelta
46
import caldav
57
import urllib3
68
from caldav.elements import dav, cdav
9+
from calendar import monthrange
710
from ics import Calendar
811
from flask import Flask
9-
from flask_ask import Ask, statement
10-
from datetime import timedelta
12+
from flask_ask import Ask, statement, request
1113

1214
app = Flask(__name__)
1315
ask = Ask(app, '/')
@@ -33,6 +35,18 @@ def connectCalendar():
3335

3436
return sorted(calendars,key=lambda calendar: str(calendar.url))
3537

38+
# split away TRIGGER and VALARM fields, since caldav library does not always parse them correctly
39+
def filterEventTriggers(events):
40+
for r in events:
41+
ev = "";
42+
ev_data = str(r._data).splitlines()
43+
for line in ev_data:
44+
if not line.lstrip().startswith("TRIGGER") and ":VALARM" not in line:
45+
ev += (line + '\n')
46+
r._data = ev
47+
48+
return events
49+
3650
def getCalDavEvents(begin, end):
3751
calendars = connectCalendar()
3852
speech_text = ""
@@ -52,22 +66,24 @@ def getCalDavEvents(begin, end):
5266

5367
log(" -> " + str(len(results)) + " Termine \n")
5468
if len(results) > 0:
69+
results = filterEventTriggers(results)
5570
eventList = eventList + flatten([Calendar(event._data).events for event in results])
5671
i = i + 1
5772

5873
if (len(eventList) <= 0):
5974
speech_text = "Es sind keine Termine eingetragen"
6075
else:
76+
log(" returning " + str(len(eventList)) + " event(s)\n")
6177
sortedEventList = sorted(eventList,key=lambda icsEvent: icsEvent.begin)
6278

6379
# pp = pprint.PrettyPrinter(indent=4)
6480
# pp.pprint(sortedEventList)
6581

66-
speech_text = "<speak>\n"
67-
speech_text += ' Es sind folgende Termine auf dem Kalender:\n'
82+
speech_text += '<speak>\n'
83+
speech_text += ' Es sind folgende Termine auf dem Kalender:\n'
6884
for icsEvent in sortedEventList:
69-
speech_text += ' <break time="1s"/> ' + icsEvent.begin.humanize(locale='de') + " ist " + icsEvent.name + '.\n'
70-
speech_text += "</speak>"
85+
speech_text += ' <break time="1s"/>' + icsEvent.begin.humanize(locale='de') + ' ist ' + getEventName(icsEvent) + '\n'
86+
speech_text += '</speak>'
7187

7288
return speech_text
7389

@@ -86,10 +102,10 @@ def getDateEvents(date, enddate):
86102
# in case that default "enddate" does not comply to "date",
87103
# the enddate is set to end of the day of "date"
88104
if date==None:
89-
date=datetime.now()
105+
date = datetime.now()
90106

91107
if enddate==None or date>=enddate:
92-
enddate = datetime(date.year, date.month, date.day + 1)
108+
enddate = getEndDate(date, request.intent.slots.date.value)
93109

94110
log(" date: " + str(date) + "\n")
95111
log(" endDate: " + str(enddate) + "\n")
@@ -99,6 +115,34 @@ def getDateEvents(date, enddate):
99115

100116
return statement(speech_text).simple_card('Kalendertermine', speech_text)
101117

118+
def getEndDate(date, orig_date):
119+
log(" orig_date: " + str(orig_date) + " " + str(type(orig_date)) + "\n")
120+
orig_date = re.sub('X$', '0', orig_date)
121+
if re.match('^\d{4}-W\d{2}$', orig_date):
122+
# this week
123+
endDate = date + timedelta(days=7)
124+
elif re.match('\d{4}-W\d{2}-WE$', orig_date):
125+
# this weekend
126+
endDate = date + timedelta(days=2)
127+
elif re.match('^\d{4}-\d{2}$', orig_date):
128+
# this month
129+
last_day = monthRange(date.year, date.month)
130+
endDate = dateTime.date(date.year, date.month, last_day)
131+
elif re.match('^\d{4}$', orig_date):
132+
# this/next year
133+
endDate = dateTime.date(date.year, 12, 31)
134+
else:
135+
endDate = datetime(date.year, date.month, date.day + 1)
136+
137+
return endDate
138+
139+
def getEventName(event):
140+
# see: https://stackoverflow.com/que stions/40135637/error-unable-to-parse-the-provided-ssml-the-provided-text-is-not-valid-ssml
141+
name = event.name
142+
name = name.replace('&', ' und ')
143+
name = name.replace('*', '')
144+
return name
145+
102146
# We do have a minor problem here. There is no timezone information in the date/time objects...
103147
# ... we assume the server's timezone, but it could be that this is wrong. So if created events are off by some hour(s)
104148
# this is the reason. If someone wants to provide a simple PR then this would be great :-)
@@ -150,7 +194,7 @@ def setEvent(date, time, duration, eventtype, location):
150194
log("ERROR: " + speech_text + "\n")
151195
else:
152196
# This could be sooo much easier if we had something like "if (calendar.isReadOnly())"
153-
i = 0;
197+
i = 0
154198
log(" gefundene Kalender: #" + str(len(calendars)) + "\n")
155199
for calendar in calendars:
156200
log(" [" + str(i + 1) + "]: " + str(calendar) + "\n")

0 commit comments

Comments
 (0)