forked from O365/python-o365
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevent.py
324 lines (271 loc) · 10.6 KB
/
event.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
import logging
import json
import requests
import time
logging.basicConfig(filename='o365.log',level=logging.DEBUG)
log = logging.getLogger(__name__)
class Event( object ):
'''
Class for managing the creation and manipluation of events in a calendar.
Methods:
create -- Creates the event in a calendar.
update -- Sends local changes up to the cloud.
delete -- Deletes event from the cloud.
toJson -- returns the json representation.
fullcalendarioJson -- gets a specific json representation used for fullcalendario.
getSubject -- gets the subject of the event.
getBody -- gets the body of the event.
getStart -- gets the starting time of the event. (struct_time)
getEnd -- gets the ending time of the event. (struct_time)
getAttendees -- gets the attendees of the event.
addAttendee -- adds an attendee to the event. update needs to be called for notification.
setSubject -- sets the subject line of the event.
setBody -- sets the body of the event.
setStart -- sets the starting time of the event. (struct_time)
setEnd -- sets the starting time of the event. (struct_time)
setAttendees -- sets the attendee list.
Variables:
time_string -- Formated time string for translation to and from json.
create_url -- url for creating a new event.
update_url -- url for updating an existing event.
delete_url -- url for deleting an event.
'''
#Formated time string for translation to and from json.
time_string = '%Y-%m-%dT%H:%M:%SZ'
#takes a calendar ID
create_url = 'https://outlook.office365.com/api/v1.0/me/calendars/{0}/events'
#takes current event ID
update_url = 'https://outlook.office365.com/api/v1.0/me/events/{0}'
#takes current event ID
delete_url = 'https://outlook.office365.com/api/v1.0/me/events/{0}'
def __init__(self,json=None,auth=None,cal=None):
'''
Creates a new event wrapper.
Keyword Argument:
json (default = None) -- json representation of an existing event. mostly just used by
this library internally for events that are downloaded by the callendar class.
auth (default = None) -- a (email,password) tuple which will be used for authentication
to office365.
cal (default = None) -- an instance of the calendar for this event to associate with.
'''
self.auth = auth
self.calendar = cal
self.attendees = []
if json:
self.json = json
self.isNew = False
else:
self.json = {}
def create(self,calendar=None):
'''
this method creates an event on the calender passed.
IMPORTANT: It returns that event now created in the calendar, if you wish
to make any changes to this event after you make it, use the returned value
and not this particular event any further.
calendar -- a calendar class onto which you want this event to be created. If this is left
empty then the event's default calendar, specified at instancing, will be used. If no
default is specified, then the event cannot be created.
'''
if not self.auth:
log.debug('failed authentication check when creating event.')
return False
if calendar:
calId = calendar.calendarId
self.calendar = calendar
log.debug('sent to passed calendar.')
elif self.calendar:
calId = self.calendar.calendarId
log.debug('sent to default calendar.')
else:
log.debug('no valid calendar to upload to.')
return False
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
log.debug('creating json for request.')
data = json.dumps(self.json)
response = None
try:
log.debug('sending post request now')
response = requests.post(self.create_url.format(calId),data,headers=headers,auth=self.auth)
log.debug('sent post request.')
except Exception as e:
if response:
log.debug('response to event creation: %s',str(response))
else:
log.error('No response, something is very wrong with create: %s',str(e))
return False
log.debug('response to event creation: %s',str(response))
return Event(response.json(),self.auth,calendar)
def update(self):
'''Updates an event that already exists in a calendar.'''
if not self.auth:
return False
if self.calendar:
calId = self.calendar.calendarId
else:
return False
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
data = json.dumps(self.json)
response = None
try:
response = requests.patch(self.update_url.format(self.json['Id']),data,headers=headers,auth=self.auth)
log.debug('sending patch request now')
except Exception as e:
if response:
log.debug('response to event creation: %s',str(response))
else:
log.error('No response, something is very wrong with update: %s',str(e))
return False
log.debug('response to event creation: %s',str(response))
return Event(response.json(),self.auth)
def delete(self):
'''
Delete's an event from the calendar it is in.
But leaves you this handle. You could then change the calendar and transfer the event to
that new calendar. You know, if that's your thing.
'''
if not self.auth:
return False
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
response = None
try:
log.debug('sending delete request')
response = requests.delete(self.delete_url.format(self.json['Id']),headers=headers,auth=self.auth)
except Exception as e:
if response:
log.debug('response to deletion: %s',str(response))
else:
log.error('No response, something is very wrong with delete: %s',str(e))
return False
return response
def toJson(self):
'''
Creates a JSON representation of the calendar event.
oh. uh. I mean it simply returns the json representation that has always been in self.json.
'''
return self.json
def fullcalendarioJson(self):
'''
returns a form of the event suitable for the vehicle booking system here.
oh the joys of having a library to yourself!
'''
ret = {}
ret['title'] = self.json['Subject']
ret['driver'] = self.json['Organizer']['EmailAddress']['Name']
ret['driverEmail'] = self.json['Organizer']['EmailAddress']['Address']
ret['start'] = self.json['Start']
ret['end'] = self.json['End']
ret['IsAllDay'] = self.json['IsAllDay']
return ret
def getSubject(self):
'''Gets event subject line.'''
return self.json['Subject']
def getBody(self):
'''Gets event body content.'''
return self.json['Body']['Content']
def getStart(self):
'''Gets event start struct_time'''
return time.strptime(self.json['Start'], self.time_string)
def getEnd(self):
'''Gets event end struct_time'''
return time.strptime(self.json['End'], self.time_string)
def getAttendees(self):
'''Gets list of event attendees.'''
return self.json['Attendees']
def setSubject(self,val):
'''sets event subject line.'''
self.json['Subject'] = val
def setBody(self,val):
'''sets event body content.'''
self.json['Body']['Content'] = val
def setStart(self,val):
'''
sets event start time.
Argument:
val - this argument can be passed in three different ways. You can pass it in as a int
or float, in which case the assumption is that it's seconds since Unix Epoch. You can
pass it in as a struct_time. Or you can pass in a string. The string must be formated
in the json style, which is %Y-%m-%dT%H:%M:%SZ. If you stray from that in your string
you will break the library.
'''
if isinstance(val,time.struct_time):
self.json['Start'] = time.strftime(self.time_string,val)
elif isinstance(val,int):
self.json['Start'] = time.strftime(self.time_string,time.gmtime(val))
elif isinstance(val,float):
self.json['Start'] = time.strftime(self.time_string,time.gmtime(val))
else:
#this last one assumes you know how to format the time string. if it brakes, check
#your time string!
self.json['Start'] = val
def setEnd(self,val):
'''
sets event end time.
Argument:
val - this argument can be passed in three different ways. You can pass it in as a int
or float, in which case the assumption is that it's seconds since Unix Epoch. You can
pass it in as a struct_time. Or you can pass in a string. The string must be formated
in the json style, which is %Y-%m-%dT%H:%M:%SZ. If you stray from that in your string
you will break the library.
'''
if isinstance(val,time.struct_time):
self.json['End'] = time.strftime(self.time_string,val)
elif isinstance(val,int):
self.json['End'] = time.strftime(self.time_string,time.gmtime(val))
elif isinstance(val,float):
self.json['End'] = time.strftime(self.time_string,time.gmtime(val))
else:
#this last one assumes you know how to format the time string. if it brakes, check
#your time string!
self.json['End'] = val
def setAttendee(self,val):
'''
set the attendee list.
val: the one argument this method takes can be very flexible. you can send:
a dictionary: this must to be a dictionary formated as such:
{"EmailAddress":{"Address":"[email protected]"}}
with other options such ass "Name" with address. but at minimum it must have this.
a list: this must to be a list of libraries formatted the way specified above,
or it can be a list of libraries objects of type Contact. The method will sort
out the libraries from the contacts.
a string: this is if you just want to throw an email address.
a contact: type Contact from this library.
For each of these argument types the appropriate action will be taken to fit them to the
needs of the library.
'''
self.json['Attendees'] = []
if isinstance(val,list):
self.json['Attendees'] = val
elif isinstance(val,dict):
self.json['Attendees'] = [val]
elif isinstance(val,str):
if '@' in val:
self.addAttendee(val)
elif isinstance(val,Contact):
self.addAttendee(val)
elif isinstance(val,Group):
self.addAttendee(val)
else:
return False
return True
def addAttendee(self,address,name=None):
'''
Adds a recipient to the attendee list.
Arguments:
address -- the email address of the person you are sending to. <<< Important that.
Address can also be of type Contact or type Group.
name -- the name of the person you are sending to. mostly just a decorator. If you
send an email address for the address arg, this will give you the ability
to set the name properly, other wise it uses the email address up to the
at sign for the name. But if you send a type Contact or type Group, this
argument is completely ignored.
'''
if isinstance(address,Contact):
self.json['Attendees'].append(address.getFirstEmailAddress())
elif isinstance(address,Group):
for con in address.contacts:
self.json['Attendees'].append(address.getFirstEmailAddress())
else:
if name is None:
name = address[:address.index('@')]
self.json['Attendees'].append({'EmailAddress':{'Address':address,'Name':name}})
#To the King!