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 _
28 from document import nodes
31 class node_database(nodes.node_database):
32 def _child_get(self, cr, name=False, parent_id=False, domain=None):
33 dirobj = self.context._dirobj
34 uid = self.context.uid
35 ctx = self.context.context.copy()
39 domain2 = domain + [('calendar_collection','=', False)]
40 res = super(node_database, self)._child_get(cr, name=name, parent_id=parent_id, domain=domain2)
41 where = [('parent_id','=',parent_id)]
42 domain2 = domain + [('calendar_collection','=', True)]
44 where.append(('name','=',name))
48 where2 = where + [('type', '=', 'directory')]
49 ids = dirobj.search(cr, uid, where2, context=ctx)
50 for dirr in dirobj.browse(cr,uid,ids,context=ctx):
51 res.append(node_calendar_collection(dirr.name,self,self.context,dirr))
54 class node_calendar_collection(nodes.node_dir):
56 "http://calendarserver.org/ns/" : ('getctag'),
59 "http://calendarserver.org/ns/" : '_get_dav',
63 def get_dav_props(self, cr):
68 def get_dav_eprop(self,cr, ns, propname):
69 if self.M_NS.has_key(ns):
70 prefix = self.M_NS[ns]
72 print "No namespace:",ns, "( for prop:", propname,")"
75 mname = prefix + "_" + propname
77 if not hasattr(self, mname):
81 m = getattr(self, mname)
84 except AttributeError, e:
85 print 'Property %s not supported' % propname
89 def _file_get(self,cr, nodename=False):
95 def _child_get(self, cr, name=False, parent_id=False, domain=None):
96 dirobj = self.context._dirobj
97 uid = self.context.uid
98 ctx = self.context.context.copy()
100 where = [('collection_id','=',self.dir_id)]
103 res = name.split('.ics')
108 where.append(('name','=',name))
111 where = where + domain
112 fil_obj = dirobj.pool.get('basic.calendar')
113 ids = fil_obj.search(cr,uid,where,context=ctx)
115 for calender in fil_obj.browse(cr, uid, ids, context=ctx):
117 res.append(node_calendar(calender.name, self, self.context, calender))
119 res.append(res_node_calendar(name, self, self.context, calender))
122 def _get_dav_owner(self, cr):
126 def get_etag(self, cr):
127 """ Get a tag, unique per object + modification.
129 see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
130 return self._get_ttag(cr) + ':' + self._get_wtag(cr)
132 def _get_wtag(self, cr):
133 """ Return the modification time as a unique, compact string """
135 wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
136 else: wtime = time.time()
139 def _get_ttag(self, cr):
140 return 'calendar collection-%d' % self.dir_id
142 def _get_dav_getctag(self, cr):
143 result = self.get_etag(cr)
147 class node_calendar(nodes.node_class):
148 our_type = 'collection'
150 "http://calendarserver.org/ns/" : ('getctag'),
151 "urn:ietf:params:xml:ns:caldav" : (
152 'calendar-description',
155 'calendar-user-address-set',
156 'schedule-inbox-URL',
157 'schedule-outbox-URL',)}
160 "http://calendarserver.org/ns/" : '_get_dav',
161 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
163 def __init__(self,path, parent, context, calendar):
164 super(node_calendar,self).__init__(path, parent,context)
165 self.calendar_id = calendar.id
166 self.mimetype = 'application/x-directory'
167 self.create_date = calendar.create_date
168 self.write_date = calendar.write_date or calendar.create_date
169 self.content_length = 0
170 self.displayname = calendar.name
171 self.cal_type = calendar.type
173 def _get_dav_getctag(self, cr):
174 result = self._get_ttag(cr) + ':' + str(time.time())
177 def match_dav_eprop(self, cr, match, ns, prop):
178 if ns == "DAV:" and prop == "getetag":
179 dirobj = self.context._dirobj
180 uid = self.context.uid
181 ctx = self.context.context.copy()
182 tem, dav_time = tuple(match.split(':'))
183 model, res_id = tuple(tem.split('_'))
184 model_obj = dirobj.pool.get(model)
185 model = model_obj.browse(cr, uid, res_id, context=ctx)
186 write_time = model.write_date or model.create_date
187 wtime = time.mktime(time.strptime(write_time,'%Y-%m-%d %H:%M:%S'))
188 if float(dav_time) == float(wtime):
191 res = super(node_calendar, self).match_dav_eprop(cr, match, ns, prop)
195 def get_domain(self, cr, filters):
197 dirobj = self.context._dirobj
198 uid = self.context.uid
199 ctx = self.context.context.copy()
200 ctx.update(self.dctx)
201 calendar_obj = dirobj.pool.get('basic.calendar')
204 if filters.localName == 'calendar-query':
206 for filter_child in filters.childNodes:
207 if filter_child.nodeType == filter_child.TEXT_NODE:
209 if filter_child.localName == 'filter':
210 for vcalendar_filter in filter_child.childNodes:
211 if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE:
213 if vcalendar_filter.localName == 'comp-filter':
214 if vcalendar_filter.getAttribute('name') == 'VCALENDAR':
215 for vevent_filter in vcalendar_filter.childNodes:
216 if vevent_filter.nodeType == vevent_filter.TEXT_NODE:
218 if vevent_filter.localName == 'comp-filter':
219 if vevent_filter.getAttribute('name') == 'VEVENT':
220 res = [('type','=','vevent')]
221 if vevent_filter.getAttribute('name') == 'VTODO':
222 res = [('type','=','vtodo')]
224 elif filters.localName == 'calendar-multiget':
226 for filter_child in filters.childNodes:
227 if filter_child.nodeType == filter_child.TEXT_NODE:
229 if filter_child.localName == 'href':
230 if not filter_child.firstChild:
232 uri = filter_child.firstChild.data
233 caluri = uri.split('/')
236 if caluri not in names : names.append(caluri)
237 res = [('name','in',names)]
241 def children(self, cr, domain=None):
242 return self._child_get(cr, domain=domain)
244 def child(self,cr, name, domain=None):
245 res = self._child_get(cr, name, domain=domain)
251 def _child_get(self, cr, name=False, parent_id=False, domain=None):
252 dirobj = self.context._dirobj
253 uid = self.context.uid
254 ctx = self.context.context.copy()
255 ctx.update(self.dctx)
258 where.append(('id','=',int(name)))
261 #for opr1, opt, opr2 in domain:
262 # if opr1 == 'type' and opr2 != self.cal_type:
265 fil_obj = dirobj.pool.get('basic.calendar')
266 ids = fil_obj.search(cr, uid, domain)
268 if self.calendar_id in ids:
269 res = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx)
274 def get_dav_props(self, cr):
277 def get_dav_eprop(self,cr, ns, propname):
278 if self.M_NS.has_key(ns):
279 prefix = self.M_NS[ns]
281 print "No namespace:",ns, "( for prop:", propname,")"
283 propname = propname.replace('-','_')
284 mname = prefix + "_" + propname
285 if not hasattr(self, mname):
289 m = getattr(self, mname)
292 except AttributeError, e:
293 print 'Property %s not supported' % propname
294 print "Exception:", e
298 def create_child(self,cr,path,data):
299 """ API function to create a child file object and node
300 Return the node_* created
302 return self.set_data(cr, data)
305 def set_data(self, cr, data, fil_obj = None):
306 uid = self.context.uid
307 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
308 return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id)
310 def get_data_len(self, cr, fil_obj = None):
311 return self.content_length
314 def _get_ttag(self,cr):
315 return 'calendar-%d' % (self.calendar_id,)
319 def get_etag(self, cr):
320 """ Get a tag, unique per object + modification.
322 see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
323 return self._get_ttag(cr) + ':' + self._get_wtag(cr)
325 def _get_wtag(self, cr):
326 """ Return the modification time as a unique, compact string """
328 wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
329 else: wtime = time.time()
336 class res_node_calendar(nodes.node_class):
339 "http://calendarserver.org/ns/" : ('getctag'),
340 "urn:ietf:params:xml:ns:caldav" : (
341 'calendar-description',
344 'calendar-user-address-set',
345 'schedule-inbox-URL',
346 'schedule-outbox-URL',)}
348 "http://calendarserver.org/ns/" : '_get_dav',
349 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
351 def __init__(self,path, parent, context, res_obj, res_model=None, res_id=None):
352 super(res_node_calendar,self).__init__(path, parent, context)
353 self.mimetype = 'text/calendar'
354 self.create_date = parent.create_date
355 self.write_date = parent.write_date or parent.create_date
356 self.calendar_id = hasattr(parent, 'calendar_id') and parent.calendar_id or False
358 if not self.calendar_id: self.calendar_id = res_obj.id
359 self.create_date = res_obj.create_date
360 self.write_date = res_obj.write_date or res_obj.create_date
361 self.displayname = res_obj.name
363 self.content_length = 0
365 self.model = res_model
368 def open(self, cr, mode=False):
369 uid = self.context.uid
370 if self.type in ('collection','database'):
372 s = StringIO.StringIO(self.get_data(cr))
378 def get_dav_props(self, cr):
381 def get_dav_eprop(self,cr, ns, propname):
382 if self.M_NS.has_key(ns):
383 prefix = self.M_NS[ns]
385 print "No namespace:",ns, "( for prop:", propname,")"
387 propname = propname.replace('-','_')
388 mname = prefix + "_" + propname
389 if not hasattr(self, mname):
393 m = getattr(self, mname)
396 except AttributeError, e:
397 print 'Property %s not supported' % propname
398 print "Exception:", e
402 def get_data(self, cr, fil_obj = None):
403 uid = self.context.uid
404 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
405 context = self.context.context.copy()
406 context.update({'model': self.model, 'res_id':self.res_id})
407 res = calendar_obj.export_cal(cr, uid, [self.calendar_id], context=context)
410 def get_data_len(self, cr, fil_obj = None):
411 return self.content_length
413 def set_data(self, cr, data, fil_obj = None):
414 uid = self.context.uid
415 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
416 return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id)
418 def _get_ttag(self,cr):
420 if self.model and self.res_id:
421 res = '%s_%d' % (self.model, self.res_id)
422 elif self.calendar_id:
423 res = '%d' % (self.calendar_id)
428 def _get_caldav_calendar_data(self, cr):
429 return self.get_data(cr)
432 def _get_caldav_calendar_description(self, cr):
433 uid = self.context.uid
434 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
435 ctx = self.context.context.copy()
436 ctx.update(self.dctx)
437 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
438 return calendar.description
441 def _get_caldav_calendar_home_set(self, cr):
442 import xml.dom.minidom
444 uid = self.context.uid
445 ctx = self.context.context.copy()
446 ctx.update(self.dctx)
447 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
449 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
450 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
451 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name)))
452 href = doc.documentElement
453 href.tagName = 'D:href'
454 href.appendChild(huri)
457 def _get_caldav_calendar_user_address_set(self, cr):
458 import xml.dom.minidom
459 dirobj = self.context._dirobj
460 uid = self.context.uid
461 ctx = self.context.context.copy()
462 ctx.update(self.dctx)
463 user_obj = self.context._dirobj.pool.get('res.users')
464 user = user_obj.browse(cr, uid, uid, context=ctx)
465 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
466 href = doc.documentElement
467 href.tagName = 'D:href'
468 huri = doc.createTextNode('MAILTO:' + user.email)
469 href.appendChild(huri)
473 def _get_caldav_schedule_inbox_URL(self, cr):
474 import xml.dom.minidom
476 uid = self.context.uid
477 ctx = self.context.context.copy()
478 ctx.update(self.dctx)
479 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
480 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
481 res = '%s/%s' %(calendar.name, calendar.collection_id.name)
482 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
483 href = doc.documentElement
484 href.tagName = 'D:href'
485 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
486 href.appendChild(huri)
491 uid = self.context.uid
493 if self.type in ('collection','database'):
495 if self.model and self.res_id:
496 document_obj = self.context._dirobj.pool.get(self.model)
499 #res = document_obj.unlink(cr, uid, [self.res_id]) #TOFIX
505 def _get_caldav_schedule_outbox_URL(self, cr):
506 return self._get_caldav_schedule_inbox_URL(cr)
509 def get_etag(self, cr):
510 """ Get a tag, unique per object + modification.
512 see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
513 return self._get_ttag(cr) + ':' + self._get_wtag(cr)
515 def _get_wtag(self, cr):
516 """ Return the modification time as a unique, compact string """
518 wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
519 else: wtime = time.time()
521 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4