summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--exchange/commands.py123
1 files changed, 64 insertions, 59 deletions
diff --git a/exchange/commands.py b/exchange/commands.py
index a2ab471..f962342 100644
--- a/exchange/commands.py
+++ b/exchange/commands.py
@@ -3,6 +3,7 @@
3Exchange Commands 3Exchange Commands
4 4
5@author: Mike Crute (mcrute@gmail.com) 5@author: Mike Crute (mcrute@gmail.com)
6@organization: American Greetings Interactive
6@date: November 10, 2008 7@date: November 10, 2008
7 8
8This is a set of classes that starts to define a set of classes for 9This is a set of classes that starts to define a set of classes for
@@ -11,14 +12,68 @@ development code but it does the trick. Watch out, it doesn't consider
11many corner cases. 12many corner cases.
12""" 13"""
13 14
14import xml.etree.cElementTree as ElementTree
15import dateutil.parser as date_parser 15import dateutil.parser as date_parser
16import xml.etree.cElementTree as ElementTree
16 17
17from httplib import HTTPSConnection
18from string import Template 18from string import Template
19from httplib import HTTPSConnection
19from datetime import datetime, timedelta 20from datetime import datetime, timedelta
20from icalendar import Calendar, Event as _Event, Alarm
21from exchange import ExchangeException, EST 21from exchange import ExchangeException, EST
22from icalendar import Calendar, Event as _Event
23
24
25class Event(_Event):
26
27 def _get_element_text(self, element, key):
28 value = element.find(key)
29
30 if hasattr(value, 'text'):
31 return value.text
32
33 def add_text(self, element, key, add_as=None):
34 value = self._get_element_text(element, key)
35
36 add_as = key if not add_as else add_as
37 self.add(add_as, value)
38
39 def add_date(self, element, key, add_as=None):
40 value = date_parser.parse(self._get_element_text(element, key))
41
42 add_as = key if not add_as else add_as
43 self.add(add_as, value)
44
45
46class ExchangeRequest(object):
47
48 def __init__(self, session, service, method='GET'):
49 self.session = session
50 self.service = service
51 self.method = method
52 self.server = session.server
53 self.username = session.username
54 self._headers = { 'Content-Type': 'text/xml',
55 'Depth': '0', 'Translate': 'f' }
56
57 @property
58 def headers(self):
59 self._headers['Cookie'] = self.session.token
60 return self._headers
61
62 @property
63 def request_url(self):
64 path = '/'.join(['exchange', self.username, self.service])
65 return '/{0}'.format(path)
66
67 def get_response(self, query=None):
68 connection = HTTPSConnection(self.server)
69 connection.request(self.method, self.request_url, query,
70 headers=self.headers)
71 resp = connection.getresponse()
72
73 if int(resp.status) > 299 or int(resp.status) < 200:
74 raise ExchangeException("%s %s" % (resp.status, resp.reason))
75
76 return resp.read()
22 77
23 78
24class ExchangeCommand(object): 79class ExchangeCommand(object):
@@ -27,18 +82,7 @@ class ExchangeCommand(object):
27 directly but should be subclassed to do useful things. 82 directly but should be subclassed to do useful things.
28 """ 83 """
29 84
30 #: Base URL for Exchange commands.
31 BASE_URL = Template("/exchange/${username}/${method}")
32
33 #: Basic headers that are required for all requests
34 BASE_HEADERS = {
35 "Content-Type": 'text/xml; charset="UTF-8"',
36 "Depth": "0",
37 "Translate": "f",
38 }
39
40 def __init__(self, session): 85 def __init__(self, session):
41 self.server = session.server
42 self.session = session 86 self.session = session
43 87
44 def _get_xml(self, **kwargs): 88 def _get_xml(self, **kwargs):
@@ -47,22 +91,13 @@ class ExchangeCommand(object):
47 @return: ElementTree response 91 @return: ElementTree response
48 """ 92 """
49 kwargs["username"] = self.session.username 93 kwargs["username"] = self.session.username
50
51 xml = self._get_query(**kwargs) 94 xml = self._get_query(**kwargs)
52 url = self.BASE_URL.substitute({ "username": self.session.username,
53 "method": self.exchange_method })
54 query = Template(xml).substitute(kwargs)
55 send_headers = self.BASE_HEADERS.copy()
56 send_headers['Cookie'] = self.session.token
57
58 conn = HTTPSConnection(self.server)
59 conn.request(self.dav_method.upper(), url, query, headers=send_headers)
60 resp = conn.getresponse()
61 95
62 if int(resp.status) > 299 or int(resp.status) < 200: 96 req = ExchangeRequest(self.session, self.exchange_method,
63 raise ExchangeException("%s %s" % (resp.status, resp.reason)) 97 self.dav_method)
98 resp = req.get_response(Template(xml).substitute(kwargs))
64 99
65 return ElementTree.fromstring(resp.read()) 100 return ElementTree.fromstring(resp)
66 101
67 def _get_query(self, **kwargs): 102 def _get_query(self, **kwargs):
68 """ 103 """
@@ -82,37 +117,10 @@ class ExchangeCommand(object):
82 return output 117 return output
83 118
84 119
85class Event(_Event):
86
87 def add_alarm(self, alarm_offset):
88 alarm = Alarm()
89 alarm.add("action", "DISPLAY")
90 alarm.add("description", "REMINDER")
91 alarm.add("trigger", timedelta(minutes=alarm_offset))
92 self.add_component(alarm)
93
94 def _get_element_text(self, element, key):
95 value = element.find(key)
96
97 if hasattr(value, 'text'):
98 return value.text
99
100 def add_text(self, element, key, add_as=None):
101 value = self._get_element_text(element, key)
102
103 add_as = key if not add_as else add_as
104 self.add(add_as, value)
105
106 def add_date(self, element, key, add_as=None):
107 value = date_parser.parse(self._get_element_text(element, key))
108
109 add_as = key if not add_as else add_as
110 self.add(add_as, value)
111
112
113class FetchCalendar(ExchangeCommand): 120class FetchCalendar(ExchangeCommand):
121
114 exchange_method = "calendar" 122 exchange_method = "calendar"
115 dav_method = "search" 123 dav_method = "SEARCH"
116 124
117 sql = """ 125 sql = """
118 SELECT 126 SELECT
@@ -148,9 +156,6 @@ class FetchCalendar(ExchangeCommand):
148 event.add_date(item, 'start_date', add_as='dtstart') 156 event.add_date(item, 'start_date', add_as='dtstart')
149 event.add_date(item, 'end_date', add_as='dtend') 157 event.add_date(item, 'end_date', add_as='dtend')
150 158
151 # TODO: Handle timezone_info
152 # TODO: Handle alarms. Previous implementation didn't work
153
154 calendar.add_component(event) 159 calendar.add_component(event)
155 160
156 return calendar 161 return calendar