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 "http://calendarserver.org/ns/" : ('getctag',),
107 'http://groupdav.org/': ('resourcetype',),
108 "urn:ietf:params:xml:ns:caldav" : (
109 'calendar-description',
112 'calendar-user-address-set',
113 'schedule-inbox-URL',
114 'schedule-outbox-URL',)}
117 'http://groupdav.org/': '_get_gdav',
118 "http://calendarserver.org/ns/" : '_get_dav',
119 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
121 http_options = { 'DAV': ['calendar-access'] }
123 def __init__(self,path, parent, context, calendar):
124 super(node_calendar,self).__init__(path, parent,context)
125 self.calendar_id = calendar.id
126 self.mimetype = 'application/x-directory'
127 self.create_date = calendar.create_date
128 self.write_date = calendar.write_date or calendar.create_date
129 self.content_length = 0
130 self.displayname = calendar.name
131 self.cal_type = calendar.type
133 def _get_dav_getctag(self, cr):
134 result = self._get_ttag(cr) + ':' + str(time.time())
137 def get_dav_resourcetype(self, cr):
138 res = [ ('collection', 'DAV:'),
139 (str(self.cal_type + '-collection'), 'http://groupdav.org/'),
140 ('calendar', 'urn:ietf:params:xml:ns:caldav') ]
143 def get_domain(self, cr, filters):
148 if filters.localName == 'calendar-query':
150 for filter_child in filters.childNodes:
151 if filter_child.nodeType == filter_child.TEXT_NODE:
153 if filter_child.localName == 'filter':
154 for vcalendar_filter in filter_child.childNodes:
155 if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE:
157 if vcalendar_filter.localName == 'comp-filter':
158 if vcalendar_filter.getAttribute('name') == 'VCALENDAR':
159 for vevent_filter in vcalendar_filter.childNodes:
160 if vevent_filter.nodeType == vevent_filter.TEXT_NODE:
162 if vevent_filter.localName == 'comp-filter':
163 if vevent_filter.getAttribute('name') == 'VEVENT':
164 res = [('type','=','vevent')]
165 if vevent_filter.getAttribute('name') == 'VTODO':
166 res = [('type','=','vtodo')]
168 elif filters.localName == 'calendar-multiget':
170 for filter_child in filters.childNodes:
171 if filter_child.nodeType == filter_child.TEXT_NODE:
173 if filter_child.localName == 'href':
174 if not filter_child.firstChild:
176 uri = filter_child.firstChild.data
177 caluri = uri.split('/')
180 if caluri not in names : names.append(caluri)
181 res = [('name','in',names)]
185 def children(self, cr, domain=None):
186 return self._child_get(cr, domain=domain)
188 def child(self,cr, name, domain=None):
189 res = self._child_get(cr, name, domain=domain)
195 def _child_get(self, cr, name=False, parent_id=False, domain=None):
196 dirobj = self.context._dirobj
197 uid = self.context.uid
198 ctx = self.context.context.copy()
199 ctx.update(self.dctx)
202 if name.endswith('.ics'):
205 where.append(('id','=',int(name)))
207 # if somebody requests any other name than the ones we
208 # generate (non-numeric), it just won't exist
209 # FIXME: however, this confuses Evolution (at least), which
210 # thinks the .ics node hadn't been saved.
216 fil_obj = dirobj.pool.get('basic.calendar')
217 ids = fil_obj.search(cr, uid, domain)
219 if self.calendar_id in ids:
220 res = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx)
223 def create_child(self, cr, path, data):
224 """ API function to create a child file object and node
225 Return the node_* created
227 # we ignore the path, it will be re-generated automatically
228 fil_obj = self.context._dirobj.pool.get('basic.calendar')
229 ctx = self.context.context.copy()
230 ctx.update(self.dctx)
231 uid = self.context.uid
233 res = self.set_data(cr, data)
236 # We arbitrarily construct only the first node of the data
237 # that have been imported. ICS may have had more elements,
238 # but only one node can be returned here.
239 assert isinstance(res[0], (int, long))
240 fnodes = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self,
241 domain=[('id','=',res[0])], context=ctx)
246 def set_data(self, cr, data, fil_obj = None):
247 uid = self.context.uid
248 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
249 res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
252 def get_data_len(self, cr, fil_obj = None):
253 return self.content_length
255 def _get_ttag(self,cr):
256 return 'calendar-%d' % (self.calendar_id,)
262 class res_node_calendar(nodes.node_class):
265 "http://calendarserver.org/ns/" : ('getctag'),
266 "urn:ietf:params:xml:ns:caldav" : (
267 'calendar-description',
270 'calendar-user-address-set',
271 'schedule-inbox-URL',
272 'schedule-outbox-URL',)}
274 "http://calendarserver.org/ns/" : '_get_dav',
275 "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
277 http_options = { 'DAV': ['calendar-access'] }
279 def __init__(self,path, parent, context, res_obj, res_model=None, res_id=None):
280 super(res_node_calendar,self).__init__(path, parent, context)
281 self.mimetype = 'text/calendar'
282 self.create_date = parent.create_date
283 self.write_date = parent.write_date or parent.create_date
284 self.calendar_id = hasattr(parent, 'calendar_id') and parent.calendar_id or False
286 if not self.calendar_id: self.calendar_id = res_obj.id
287 pr = res_obj.perm_read()[0]
288 self.create_date = pr.get('create_date')
289 self.write_date = pr.get('write_date') or pr.get('create_date')
290 self.displayname = res_obj.name
292 self.content_length = 0
294 self.model = res_model
297 def open(self, cr, mode=False):
298 uid = self.context.uid
299 if self.type in ('collection','database'):
301 s = StringIO.StringIO(self.get_data(cr))
305 def get_data(self, cr, fil_obj = None):
306 uid = self.context.uid
307 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
308 context = self.context.context.copy()
309 context.update({'model': self.model, 'res_id':self.res_id})
310 res = calendar_obj.export_cal(cr, uid, [self.calendar_id], context=context)
313 def get_data_len(self, cr, fil_obj = None):
314 return self.content_length
316 def set_data(self, cr, data, fil_obj = None):
317 uid = self.context.uid
318 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
319 res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
322 def _get_ttag(self,cr):
324 if self.model and self.res_id:
325 res = '%s_%d' % (self.model, self.res_id)
326 elif self.calendar_id:
327 res = '%d' % (self.calendar_id)
330 def _get_caldav_calendar_data(self, cr):
331 return self.get_data(cr)
334 def _get_caldav_calendar_description(self, cr):
335 uid = self.context.uid
336 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
337 ctx = self.context.context.copy()
338 ctx.update(self.dctx)
339 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
340 return calendar.description
343 def _get_caldav_calendar_home_set(self, cr):
344 import xml.dom.minidom
346 uid = self.context.uid
347 ctx = self.context.context.copy()
348 ctx.update(self.dctx)
349 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
351 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
352 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
353 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name)))
354 href = doc.documentElement
355 href.tagName = 'D:href'
356 href.appendChild(huri)
359 def _get_caldav_calendar_user_address_set(self, cr):
360 import xml.dom.minidom
361 dirobj = self.context._dirobj
362 uid = self.context.uid
363 ctx = self.context.context.copy()
364 ctx.update(self.dctx)
365 user_obj = self.context._dirobj.pool.get('res.users')
366 user = user_obj.browse(cr, uid, uid, context=ctx)
367 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
368 href = doc.documentElement
369 href.tagName = 'D:href'
370 huri = doc.createTextNode('MAILTO:' + user.email)
371 href.appendChild(huri)
375 def _get_caldav_schedule_inbox_URL(self, cr):
376 import xml.dom.minidom
378 uid = self.context.uid
379 ctx = self.context.context.copy()
380 ctx.update(self.dctx)
381 calendar_obj = self.context._dirobj.pool.get('basic.calendar')
382 calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
383 res = '%s/%s' %(calendar.name, calendar.collection_id.name)
384 doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
385 href = doc.documentElement
386 href.tagName = 'D:href'
387 huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
388 href.appendChild(huri)
393 uid = self.context.uid
395 if self.type in ('collection','database'):
397 if self.model and self.res_id:
398 document_obj = self.context._dirobj.pool.get(self.model)
400 res = document_obj.unlink(cr, uid, [self.res_id])
404 def _get_caldav_schedule_outbox_URL(self, cr):
405 return self._get_caldav_schedule_inbox_URL(cr)
407 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4