diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index cb496d12de0..3c7bf49a8fa 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -21,6 +21,7 @@ import calendar import calendar_collection +import caldav import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py new file mode 100644 index 00000000000..224d1ba176c --- /dev/null +++ b/addons/caldav/caldav.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from document_webdav import webdav +import tools +from DAV.propfind import PROPFIND + + +super_mk_prop_response = webdav.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + res = super_mk_prop_response(self, uri,good_props,bad_props,doc) + uris = uri.split('/') + if uri[-1] in ('Calendars'): + ad = doc.createElement('calendar') + ad.setAttribute('xmlns', 'urn:ietf:params:xml:ns:caldav') + cols = res.getElementsByTagName('D:collection') + if cols: + cols[0].parentNode.appendChild(ad) + #cols[0].parentNode.appendChild(vc) + return res + +PROPFIND.mk_prop_response = mk_prop_response diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 365cf6ab1ee..ffc300836b7 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -54,16 +54,10 @@ class node_database(nodes.node_database): class node_calendar_collection(nodes.node_dir): PROPS = { "http://calendarserver.org/ns/" : ('getctag'), - "urn:ietf:params:xml:ns:caldav" : ( - 'calendar-description', - 'calendar-data', - 'calendar-home-set', - 'calendar-user-address-set', - 'schedule-inbox-URL', - 'schedule-outbox-URL',)} + } M_NS = { "http://calendarserver.org/ns/" : '_get_dav', - "urn:ietf:params:xml:ns:caldav" : '_get_caldav'} + } def get_dav_props(self, cr): return self.PROPS @@ -89,6 +83,59 @@ class node_calendar_collection(nodes.node_dir): print "Exception:", e return None + def _file_get(self,cr, nodename=False): + return [] + + + def get_domain(self, cr, filters): + res = [] + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + calendar_obj = dirobj.pool.get('basic.calendar') + if not filters: + return res + if filters.localName == 'calendar-query': + res = [] + for filter_child in filters.childNodes: + if filter_child.nodeType == filter_child.TEXT_NODE: + continue + if filter_child.localName == 'filter': + for vcalendar_filter in filter_child.childNodes: + if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE: + continue + if vcalendar_filter.localName == 'comp-filter': + if vcalendar_filter.getAttribute('name') == 'VCALENDAR': + for vevent_filter in vcalendar_filter.childNodes: + if vevent_filter.nodeType == vevent_filter.TEXT_NODE: + continue + if vevent_filter.localName == 'comp-filter': + if vevent_filter.getAttribute('name') == 'VEVENT': + res = [('type','=','vevent')] + if vevent_filter.getAttribute('name') == 'VTODO': + res = [('type','=','vtodo')] + + return res + elif filters.localName == 'calendar-multiget': + ids = [] + for filter_child in filters.childNodes: + if filter_child.nodeType == filter_child.TEXT_NODE: + continue + if filter_child.localName == 'href': + if not filter_child.firstChild: + continue + uri = filter_child.firstChild.data + caluri = uri.split('/') + if len(caluri): + caluri = caluri[-1] + calendar = calendar_obj.name_search(cr, uid, caluri) + if calendar: + calendar_id, calendar_name = calendar[0] + ids.append(calendar_id) + return [('id', 'in', ids)] + return res + def _child_get(self, cr, name=False, parent_id=False, domain=None): dirobj = self.context._dirobj uid = self.context.uid @@ -99,7 +146,7 @@ class node_calendar_collection(nodes.node_dir): where.append(('name','=',name)) if not domain: domain = [] - + where = where + domain fil_obj = dirobj.pool.get('basic.calendar') ids = fil_obj.search(cr,uid,where,context=ctx) res = [] @@ -130,31 +177,110 @@ class node_calendar_collection(nodes.node_dir): def _get_dav_getctag(self, cr): result = self.get_etag(cr) - return str(result) + return str(result) + + +class node_calendar(nodes.node_class): + our_type = 'file' + PROPS = { + "http://calendarserver.org/ns/" : ('getctag'), + "urn:ietf:params:xml:ns:caldav" : ( + 'calendar-description', + 'calendar-data', + 'calendar-home-set', + 'calendar-user-address-set', + 'schedule-inbox-URL', + 'schedule-outbox-URL',)} + M_NS = { + "http://calendarserver.org/ns/" : '_get_dav', + "urn:ietf:params:xml:ns:caldav" : '_get_caldav'} + + def __init__(self,path, parent, context, calendar): + super(node_calendar,self).__init__(path, parent,context) + self.calendar_id = calendar.id + self.mimetype = 'ics' + self.create_date = calendar.create_date + self.write_date = calendar.write_date or calendar.create_date + self.content_length = 0 + self.displayname = calendar.name + + def open(self, cr, mode=False): + uid = self.context.uid + if self.type in ('collection','database'): + return False + fobj = self.context._dirobj.pool.get('basic.calendar').browse(cr, uid, self.calendar_id, context=self.context.context) + s = StringIO.StringIO(self.get_data(cr, fobj)) + s.name = self + return s + + + + def get_dav_props(self, cr): + return self.PROPS + + def get_dav_eprop(self,cr, ns, propname): + if self.M_NS.has_key(ns): + prefix = self.M_NS[ns] + else: + print "No namespace:",ns, "( for prop:", propname,")" + return None + propname = propname.replace('-','_') + mname = prefix + "_" + propname + if not hasattr(self, mname): + return None + + try: + m = getattr(self, mname) + r = m(cr) + return r + except AttributeError, e: + print 'Property %s not supported' % propname + print "Exception:", e + return None + + + def get_data(self, cr, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.export_cal(cr, uid, [self.calendar_id]) + + def get_data_len(self, cr, fil_obj = None): + return self.content_length + + def set_data(self, cr, data, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) + + def _get_ttag(self,cr): + return 'calendar-%d' % self.calendar_id + + + + def _get_caldav_calendar_data(self, cr): + res = self.get_data(cr) def _get_caldav_calendar_description(self, cr): - dirobj = self.context._dirobj uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') ctx = self.context.context.copy() - ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_description(cr, uid, ids, context=ctx) - return res - - def _get_caldav_calendar_data(self, cr): - return self.get_data(cr) + ctx.update(self.dctx) + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + return calendar.description + def _get_caldav_calendar_home_set(self, cr): import xml.dom.minidom - import urllib - dirobj = self.context._dirobj + import urllib uid = self.context.uid ctx = self.context.context.copy() ctx.update(self.dctx) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) - root_cal_dir = dirobj._get_root_calendar_directory(cr, uid, context=ctx) - huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, root_cal_dir))) + + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name))) href = doc.documentElement href.tagName = 'D:href' href.appendChild(huri) @@ -178,14 +304,13 @@ class node_calendar_collection(nodes.node_dir): def _get_caldav_schedule_inbox_URL(self, cr): import xml.dom.minidom - import urllib - dirobj = self.context._dirobj + import urllib uid = self.context.uid ctx = self.context.context.copy() ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_schedule_inbox_URL(cr, uid, ids, context=ctx) - + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + res = '%s/%s' %(calendar.name, calendar.collection_id.name) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) href = doc.documentElement href.tagName = 'D:href' @@ -196,67 +321,7 @@ class node_calendar_collection(nodes.node_dir): def _get_caldav_schedule_outbox_URL(self, cr): - import xml.dom.minidom - import urllib - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_schedule_outbox_URL(cr, uid, ids, context=ctx) - - doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) - href = doc.documentElement - href.tagName = 'D:href' - huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res))) - href.appendChild(huri) - return href - - -class node_calendar(nodes.node_class): - our_type = 'file' - def __init__(self,path, parent, context, calendar): - super(node_calendar,self).__init__(path, parent,context) - self.calendar_id = calendar.id - self.mimetype = 'ics' - self.create_date = calendar.create_date - self.write_date = calendar.write_date or calendar.create_date - self.content_length = 0 - self.displayname = calendar.name - - def open(self, cr, mode=False): - uid = self.context.uid - if self.type in ('collection','database'): - return False - fobj = self.context._dirobj.pool.get('basic.calendar').browse(cr, uid, self.calendar_id, context=self.context.context) - s = StringIO.StringIO(self.get_data(cr, fobj)) - s.name = self - return s - - def get_dav_props(self, cr): - res = {} - return res - - def get_dav_eprop(self,cr,ns,prop): - return None - - - def get_data(self, cr, fil_obj = None): - uid = self.context.uid - calendar_obj = self.context._dirobj.pool.get('basic.calendar') - return calendar_obj.export_cal(cr, uid, [self.calendar_id]) - - def get_data_len(self, cr, fil_obj = None): - return self.content_length - - def set_data(self, cr, data, fil_obj = None): - uid = self.context.uid - calendar_obj = self.context._dirobj.pool.get('basic.calendar') - return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) - - def _get_ttag(self,cr): - return 'calendar-%d' % self.calendar_id - + return _get_caldav_schedule_inbox_URL(cr) def get_etag(self, cr): @@ -270,5 +335,5 @@ class node_calendar(nodes.node_class): if self.write_date: wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S')) else: wtime = time.time() - return str(wtime) + return str(wtime) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4 diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index c982d695fac..4c1003023ae 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -70,7 +70,8 @@ form
- + + @@ -112,7 +113,8 @@ tree - + + diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index 4f672838155..52a1e8a56e3 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -431,6 +431,8 @@ class Calendar(CalDAV, osv.osv): 'user_id': fields.many2one('res.users', 'Owner'), 'collection_id': fields.many2one('document.directory', 'Collection', \ required=True), + 'type': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO')], \ + string="Type", size=64), 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date'), 'write_date': fields.datetime('Modifided Date'), diff --git a/addons/document/nodes.py b/addons/document/nodes.py index b35dd1ed1f2..e10d0934eef 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -109,11 +109,11 @@ class node_class(object): s.append(self.path) return s #map(lambda x: '/' +x, s) - def children(self, cr): + def children(self, cr, domain=None): print "node_class.children()" return [] #stub - def child(self,cr, name): + def child(self,cr, name, domain=None): print "node_class.child()" return None @@ -155,6 +155,9 @@ class node_class(object): def get_dav_eprop(self,cr,ns,prop): return None + def get_domain(self, cr, filters): + return [] + class node_database(node_class): """ A node representing the database directory @@ -163,12 +166,12 @@ class node_database(node_class): def __init__(self, path=[], parent=False, context=None): super(node_database,self).__init__(path, parent, context) - def children(self,cr): - res = self._child_get(cr) + self._file_get(cr) + def children(self, cr, domain=None): + res = self._child_get(cr, domain=domain) + self._file_get(cr) return res - def child(self, cr, name): - res = self._child_get(cr,name) + def child(self, cr, name, domain=None): + res = self._child_get(cr, name, domain=None) if res: return res[0] res = self._file_get(cr,name) @@ -264,8 +267,8 @@ class node_dir(node_database): - def _child_get(self, cr, name = None): - return super(node_dir,self)._child_get(cr, name, self.dir_id) + def _child_get(self, cr, name=None, domain=None): + return super(node_dir,self)._child_get(cr, name, self.dir_id, domain=domain) def create_child_collection(self, cr, objname): object2 = False @@ -359,16 +362,16 @@ class node_res_dir(node_class): for dfld in dirr.dctx_ids: self.dctx_dict['dctx_' + dfld.field] = dfld.expr - def children(self,cr): - return self._child_get(cr) + def children(self, cr, domain=None): + return self._child_get(cr, domain=domain) - def child(self,cr, name): - res = self._child_get(cr,name) + def child(self,cr, name, domain=None): + res = self._child_get(cr, name, domain=domain) if res: return res[0] return None - def _child_get(self,cr,name = None): + def _child_get(self,cr, name = None, domain=None): """ return virtual children of resource, based on the foreign object. @@ -455,11 +458,11 @@ class node_res_obj(node_class): else: self.res_id = res_id - def children(self,cr): - return self._child_get(cr) + self._file_get(cr) + def children(self, cr, domain=None): + return self._child_get(cr, domain=domain) + self._file_get(cr) - def child(self,cr, name): - res = self._child_get(cr,name) + def child(self,cr, name, domain=None): + res = self._child_get(cr, name, domain=domain) if res: return res[0] res = self._file_get(cr,name) @@ -514,7 +517,7 @@ class node_res_obj(node_class): return ('vevent-collection','http://groupdav.org/') return None - def _child_get(self,cr,name = None): + def _child_get(self,cr, name=None, domain=None): dirobj = self.context._dirobj uid = self.context.uid ctx = self.context.context.copy() @@ -792,147 +795,3 @@ class node_content(node_class): def _get_ttag(self,cr): return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '') - -class old_class(): - # the old code, remove.. - def __init__(self, cr, uid, path, object, object2=False, context={}, content=False, type='collection', root=False): - self.cr = cr - def _file_get(self, nodename=False): - if not self.object: - return [] - pool = pooler.get_pool(self.cr.dbname) - fobj = pool.get('ir.attachment') - res2 = [] - where = [] - if self.object2: - where.append( ('res_model','=',self.object2._name) ) - where.append( ('res_id','=',self.object2.id) ) - else: - where.append( ('parent_id','=',self.object.id) ) - where.append( ('res_id','=',False) ) - if nodename: - where.append( (fobj._rec_name,'=',nodename) ) - for content in self.object.content_ids: - res3 = content._table._file_get(self,nodename,content) - if res3: - res2.extend(res3) - - ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ]) - if self.object and self.root and (self.object.type=='ressource'): - ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ]) - res = fobj.browse(self.cr, self.uid, ids, context=self.context) - return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=False), res) + res2 - - def get_translation(self,value,lang): - # Must go, it works on arbitrary models and could be ambiguous. - result = value - pool = pooler.get_pool(self.cr.dbname) - translation_ids = pool.get('ir.translation').search(self.cr, self.uid, [('value','=',value),('lang','=',lang),('type','=','model')]) - if len(translation_ids): - tran_id = translation_ids[0] - translation = pool.get('ir.translation').read(self.cr, self.uid, tran_id, ['res_id','name']) - res_model,field_name = tuple(translation['name'].split(',')) - res_id = translation['res_id'] - res = pool.get(res_model).read(self.cr, self.uid, res_id, [field_name]) - if res: - result = res[field_name] - return result - - def directory_list_for_child(self,nodename,parent=False): - pool = pooler.get_pool(self.cr.dbname) - where = [] - if nodename: - nodename = self.get_translation(nodename, self.context['lang']) - where.append(('name','=',nodename)) - if (self.object and self.object.type=='directory') or not self.object2: - where.append(('parent_id','=',self.object and self.object.id or False)) - else: - where.append(('parent_id','=',False)) - if self.object: - where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id)) - else: - where.append(('ressource_parent_type_id','=',False)) - - ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)]) - if self.object2: - ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)]) - res = pool.get('document.directory').browse(self.cr, self.uid, ids, self.context) - return res - - def _child_get(self, nodename=False): - if self.type not in ('collection','database'): - return [] - res = self.directory_list_for_child(nodename) - result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, context=self.context, root=self.root), res) - if self.type=='database': - pool = pooler.get_pool(self.cr.dbname) - fobj = pool.get('ir.attachment') - vargs = [('parent_id','=',False),('res_id','=',False)] - if nodename: - vargs.append((fobj._rec_name,'=',nodename)) - file_ids=fobj.search(self.cr,self.uid,vargs) - - res = fobj.browse(self.cr, self.uid, file_ids, context=self.context) - result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=self.root), res) - if self.type=='collection' and self.object.type=="ressource": - where = self.object.domain and eval(self.object.domain, {'active_id':self.root, 'uid':self.uid}) or [] - pool = pooler.get_pool(self.cr.dbname) - obj = pool.get(self.object.ressource_type_id.model) - _dirname_field = obj._rec_name - if len(obj.fields_get(self.cr, self.uid, ['dirname'])): - _dirname_field = 'dirname' - - name_for = obj._name.split('.')[-1] - if nodename and nodename.find(name_for) == 0 : - id = int(nodename.replace(name_for,'')) - where.append(('id','=',id)) - elif nodename: - if nodename.find('__') : - nodename=nodename.replace('__','/') - for invalid in INVALID_CHARS: - if nodename.find(INVALID_CHARS[invalid]) : - nodename=nodename.replace(INVALID_CHARS[invalid],invalid) - nodename = self.get_translation(nodename, self.context['lang']) - where.append((_dirname_field,'=',nodename)) - - if self.object.ressource_tree: - if obj._parent_name in obj.fields_get(self.cr,self.uid): - where.append((obj._parent_name,'=',self.object2 and self.object2.id or False)) - ids = obj.search(self.cr, self.uid, where) - res = obj.browse(self.cr, self.uid, ids,self.context) - result+= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res) - return result - else : - if self.object2: - return result - else: - if self.object2: - return result - - - ids = obj.search(self.cr, self.uid, where) - res = obj.browse(self.cr, self.uid, ids,self.context) - for r in res: - if len(obj.fields_get(self.cr, self.uid, [_dirname_field])): - r.name = eval('r.'+_dirname_field) - else: - r.name = False - if not r.name: - r.name = name_for + '%d'%r.id - for invalid in INVALID_CHARS: - if r.name.find(invalid) : - r.name = r.name.replace(invalid,INVALID_CHARS[invalid]) - result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res) - if result2: - if self.object.ressource_tree: - result += result2 - else: - result = result2 - return result - - - def path_get(self): - path = self.path - if self.path[0]=='/': - path = self.path[1:] - return path diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 36b7313a0fa..1b77ea67832 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -135,8 +135,8 @@ class openerp_dav_handler(dav_interface): cr.close() return self.db_name_list - def get_childs(self,uri): - """ return the child objects as self.baseuris for the given URI """ + def get_childs(self,uri, filters=None): + """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -158,14 +158,16 @@ class openerp_dav_handler(dav_interface): fp = '/'.join(fp) else: fp = None - for d in node.children(cr): + domain = None + if filters: + domain = node.get_domain(cr, filters) + for d in node.children(cr, domain): self.parent.log_message('child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: result.append( self.urijoin(dbname,d.path) ) if cr: cr.close() - return result def uri2local(self, uri):