1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program 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
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from osv import osv, fields
23 from tools.translate import _
27 from document import nodes
30 class node_database(nodes.node_database):
31 def _child_get(self, cr, name=False, parent_id=False, domain=None):
32 dirobj = self.context._dirobj
33 uid = self.context.uid
34 ctx = self.context.context.copy()
38 domain2 = domain + [('calendar_collection','=', False)]
39 res = super(node_database, self)._child_get(cr, name=name, parent_id=parent_id, domain=domain2)
40 where = [('parent_id','=',parent_id)]
41 domain2 = domain + [('calendar_collection','=', True)]
43 where.append(('name','=',name))
47 where2 = where + [('type', '=', 'directory')]
48 ids = dirobj.search(cr, uid, where2, context=ctx)
49 for dirr in dirobj.browse(cr,uid,ids,context=ctx):
50 res.append(node_calendar_collection(dirr.name,self,self.context,dirr))
53 class node_calendar_collection(nodes.node_dir):
55 "http://calendarserver.org/ns/" : ('getctag',),
58 "http://calendarserver.org/ns/" : '_get_dav',
61 http_options = { 'DAV': ['calendar-access'] }
63 def _file_get(self,cr, nodename=False):
66 def _child_get(self, cr, name=False, parent_id=False, domain=None):
67 dirobj = self.context._dirobj
68 uid = self.context.uid
69 ctx = self.context.context.copy()
71 where = [('collection_id','=',self.dir_id)]
73 if name and name.endswith('.ics'):
77 where.append(('name','=',name))
80 where = where + domain
81 fil_obj = dirobj.pool.get('basic.calendar')
82 ids = fil_obj.search(cr,uid,where,context=ctx)
84 for cal in fil_obj.browse(cr, uid, ids, context=ctx):
85 if (not name) or not ext:
86 res.append(node_calendar(cal.name, self, self.context, cal))
88 res.append(res_node_calendar(cal.name+'.ics', self, self.context, cal))
89 # May be both of them!
92 def _get_dav_owner(self, cr):
96 def _get_ttag(self, cr):
97 return 'calen-dir-%d' % self.dir_id
99 def _get_dav_getctag(self, cr):
100 result = self.get_etag(cr)
103 class node_calendar(nodes.node_class):
104 our_type = 'collection'
106 "DAV:": ('principal-collection-set'),
107 "http://cal.me.com/_namespace/" : ('user-state'),
108 "http://calendarserver.org/ns/" : (
112 'http://groupdav.org/': ('resourcetype',),
113 "urn:ietf:params:xml:ns:caldav" : (
114 'calendar-description',
117 'calendar-user-address-set',
118 'schedule-inbox-URL',
119 'schedule-outbox-URL',)}
122 "http://cal.me.com/_namespace/": '_get_dav',
123 'http://groupdav.org/': '_get_gdav',
124 "http://calendarserver.org/ns/" : '_get_dav',
125 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
127 http_options = { 'DAV': ['calendar-access'] }
129 def __init__(self,path, parent, context, calendar):
130 super(node_calendar,self).__init__(path, parent,context)
131 self.calendar_id = calendar.id
132 self.mimetype = 'application/x-directory'
133 self.create_date = calendar.create_date
134 self.write_date = calendar.write_date or calendar.create_date
135 self.content_length = 0
136 self.displayname = calendar.name
137 self.cal_type = calendar.type
139 def _get_dav_getctag(self, cr):
140 result = self._get_ttag(cr) + ':' + str(time.time())
143 def _get_dav_dropbox_home_URL(self, cr):
144 import xml.dom.minidom
146 uid = self.context.uid
147 ctx = self.context.context.copy()
148 ctx.update(self.dctx)
149 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
150 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
151 res = '%s/%s' %(calendar.collection_id.name, calendar.name)
152 url = urllib.quote('/%s/%s' % (cr.dbname, res))
155 def _get_dav_notification_URL(self, cr):
156 import xml.dom.minidom
158 uid = self.context.uid
159 ctx = self.context.context.copy()
160 ctx.update(self.dctx)
161 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
162 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
163 res = '%s/%s' %(calendar.collection_id.name, calendar.name)
164 url = urllib.quote('/%s/%s' % (cr.dbname, res))
167 def _get_dav_user_state(self, cr):
172 def get_dav_resourcetype(self, cr):
173 res = [ ('collection', 'DAV:'),
174 (str(self.cal_type + '-collection'), 'http://groupdav.org/'),
175 ('calendar', 'urn:ietf:params:xml:ns:caldav') ]
178 def get_domain(self, cr, filters):
183 if filters.localName == 'calendar-query':
185 for filter_child in filters.childNodes:
186 if filter_child.nodeType == filter_child.TEXT_NODE:
188 if filter_child.localName == 'filter':
189 for vcalendar_filter in filter_child.childNodes:
190 if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE:
192 if vcalendar_filter.localName == 'comp-filter':
193 if vcalendar_filter.getAttribute('name') == 'VCALENDAR':
194 for vevent_filter in vcalendar_filter.childNodes:
195 if vevent_filter.nodeType == vevent_filter.TEXT_NODE:
197 if vevent_filter.localName == 'comp-filter':
198 if vevent_filter.getAttribute('name') == 'VEVENT':
199 res = [('type','=','vevent')]
200 if vevent_filter.getAttribute('name') == 'VTODO':
201 res = [('type','=','vtodo')]
203 elif filters.localName == 'calendar-multiget':
205 for filter_child in filters.childNodes:
206 if filter_child.nodeType == filter_child.TEXT_NODE:
208 if filter_child.localName == 'href':
209 if not filter_child.firstChild:
211 uri = filter_child.firstChild.data
212 caluri = uri.split('/')
215 if caluri not in names : names.append(caluri)
216 res = [('name','in',names)]
220 def children(self, cr, domain=None):
221 return self._child_get(cr, domain=domain)
223 def child(self,cr, name, domain=None):
224 res = self._child_get(cr, name, domain=domain)
230 def _child_get(self, cr, name=False, parent_id=False, domain=None):
231 dirobj = self.context._dirobj
232 uid = self.context.uid
233 ctx = self.context.context.copy()
234 ctx.update(self.dctx)
237 if name.endswith('.ics'):
240 where.append(('id','=',int(name)))
242 # if somebody requests any other name than the ones we
243 # generate (non-numeric), it just won't exist
244 # FIXME: however, this confuses Evolution (at least), which
245 # thinks the .ics node hadn't been saved.
251 fil_obj = dirobj.pool.get('basic.calendar')
252 ids = fil_obj.search(cr, uid, domain)
254 if self.calendar_id in ids:
255 res = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx)
258 def create_child(self, cr, path, data):
259 """ API function to create a child file object and node
260 Return the node_* created
262 # we ignore the path, it will be re-generated automatically
263 fil_obj = self.context._dirobj.pool.get('basic.calendar')
264 ctx = self.context.context.copy()
265 ctx.update(self.dctx)
266 uid = self.context.uid
268 res = self.set_data(cr, data)
271 # We arbitrarily construct only the first node of the data
272 # that have been imported. ICS may have had more elements,
273 # but only one node can be returned here.
274 assert isinstance(res[0], (int, long))
275 fnodes = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self,
276 domain=[('id','=',res[0])], context=ctx)
281 def set_data(self, cr, data, fil_obj = None):
282 uid = self.context.uid
283 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
284 res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
287 def get_data_len(self, cr, fil_obj = None):
288 return self.content_length
290 def _get_ttag(self,cr):
291 return 'calendar-%d' % (self.calendar_id,)
297 def _get_caldav_calendar_data(self, cr):
299 for child in self.children(cr):
300 res.append(child._get_caldav_calendar_data(cr))
303 def _get_caldav_calendar_description(self, cr):
304 uid = self.context.uid
305 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
306 ctx = self.context.context.copy()
307 ctx.update(self.dctx)
308 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
309 return calendar.description
311 def _get_dav_principal_collection_set(self, uri):
313 uid = self.context.uid
314 ctx = self.context.context.copy()
315 ctx.update(self.dctx)
316 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
317 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
318 res = '%s/%s' %(calendar.collection_id.name, calendar.name)
319 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
320 href = doc.documentElement
321 href.tagName = 'D:href'
322 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
323 href.appendChild(huri)
326 def _get_caldav_calendar_home_set(self, cr):
327 import xml.dom.minidom
329 uid = self.context.uid
330 ctx = self.context.context.copy()
331 ctx.update(self.dctx)
332 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
334 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
335 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
336 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name)))
337 href = doc.documentElement
338 href.tagName = 'D:href'
339 href.appendChild(huri)
342 def _get_caldav_calendar_user_address_set(self, cr):
343 import xml.dom.minidom
344 dirobj = self.context._dirobj
345 uid = self.context.uid
346 ctx = self.context.context.copy()
347 ctx.update(self.dctx)
348 user_obj = self.context._dirobj.pool.get('res.users')
349 user = user_obj.browse(cr, uid, uid, context=ctx)
350 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
351 href = doc.documentElement
352 href.tagName = 'D:href'
353 huri = doc.createTextNode('MAILTO:' + str(user.email) or str(user.name))
354 href.appendChild(huri)
357 def _get_caldav_schedule_outbox_URL(self, cr):
358 return self._get_caldav_schedule_inbox_URL(cr)
360 def _get_caldav_schedule_inbox_URL(self, cr):
361 import xml.dom.minidom
363 uid = self.context.uid
364 ctx = self.context.context.copy()
365 ctx.update(self.dctx)
366 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
367 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
368 res = '%s/%s' %(calendar.collection_id.name, calendar.name)
369 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
370 href = doc.documentElement
371 href.tagName = 'D:href'
372 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
373 href.appendChild(huri)
377 class res_node_calendar(nodes.node_class):
380 "http://calendarserver.org/ns/" : ('getctag'),
381 "urn:ietf:params:xml:ns:caldav" : (
382 'calendar-description',
385 'calendar-user-address-set',
386 'schedule-inbox-URL',
387 'schedule-outbox-URL',)}
389 "http://calendarserver.org/ns/" : '_get_dav',
390 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
392 http_options = { 'DAV': ['calendar-access'] }
394 def __init__(self,path, parent, context, res_obj, res_model=None, res_id=None):
395 super(res_node_calendar,self).__init__(path, parent, context)
396 self.mimetype = 'text/calendar'
397 self.create_date = parent.create_date
398 self.write_date = parent.write_date or parent.create_date
399 self.calendar_id = hasattr(parent, 'calendar_id') and parent.calendar_id or False
401 if not self.calendar_id: self.calendar_id = res_obj.id
402 pr = res_obj.perm_read()[0]
403 self.create_date = pr.get('create_date')
404 self.write_date = pr.get('write_date') or pr.get('create_date')
405 self.displayname = res_obj.name
407 self.content_length = 0
409 self.model = res_model
412 def open(self, cr, mode=False):
413 uid = self.context.uid
414 if self.type in ('collection','database'):
416 s = StringIO.StringIO(self.get_data(cr))
420 def get_data(self, cr, fil_obj = None):
421 uid = self.context.uid
422 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
423 context = self.context.context.copy()
424 context.update({'model': self.model, 'res_id':self.res_id})
425 res = calendar_obj.export_cal(cr, uid, [self.calendar_id], context=context)
428 def _get_caldav_calendar_data(self, cr):
429 return self.get_data(cr)
431 def get_data_len(self, cr, fil_obj = None):
432 return self.content_length
434 def set_data(self, cr, data, fil_obj = None):
435 uid = self.context.uid
436 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
437 res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
440 def _get_ttag(self,cr):
442 if self.model and self.res_id:
443 res = '%s_%d' % (self.model, self.res_id)
444 elif self.calendar_id:
445 res = '%d' % (self.calendar_id)
450 uid = self.context.uid
452 if self.type in ('collection','database'):
454 if self.model and self.res_id:
455 document_obj = self.context._dirobj.pool.get(self.model)
457 res = document_obj.unlink(cr, uid, [self.res_id])
463 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4