From e246a6bfe0e89f5c45cca17292837f3e520fa2c9 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 22 Apr 2010 18:20:41 +0530 Subject: [PATCH] [IMP+REF] caldav bzr revid: hmo@tinyerp.com-20100422125041-2x1fkswvf2gab05p --- addons/caldav/caldav.py | 9 +- addons/caldav/caldav_node.py | 319 ++++++++++++++++-------- addons/caldav/calendar.py | 28 +-- addons/document_webdav/dav_fs.py | 2 +- addons/project_caldav/project_caldav.py | 2 + 5 files changed, 240 insertions(+), 120 deletions(-) diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py index 730bfda816a..f760421dfe5 100644 --- a/addons/caldav/caldav.py +++ b/addons/caldav/caldav.py @@ -26,10 +26,13 @@ import urlparse urlparse.uses_netloc.append('caldav') urlparse.uses_netloc.append('caldavs') super_mk_prop_response = webdav.mk_prop_response -def mk_prop_response(self,uri,good_props,bad_props,doc): +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'): + uris = uri.split('/') + calendar = False + if 'http://calendarserver.org/ns/' in good_props or 'http://calendarserver.org/ns/' in bad_props: + calendar = True + if calendar: ad = doc.createElement('calendar') ad.setAttribute('xmlns', 'urn:ietf:params:xml:ns:caldav') cols = res.getElementsByTagName('D:collection') diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 81135751464..e8887e12b56 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -57,29 +57,15 @@ class node_calendar_collection(nodes.node_dir): } M_NS = { "http://calendarserver.org/ns/" : '_get_dav', - } - headers = None + } + + def get_dav_props(self, cr): return self.PROPS - def match_dav_eprop(self, cr, match, ns, prop): - if ns == "DAV:" and prop == "getetag": - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - tem, dav_time = tuple(match.split(':')) - title, cal_id, model, res_id = tuple(tem.split('-')) - model_obj = dirobj.pool.get(model) - model = model_obj.browse(cr, uid, res_id, context=ctx) - write_time = model.write_date or model.create_date - wtime = time.mktime(time.strptime(write_time,'%Y-%m-%d %H:%M:%S')) - if dav_time <= wtime: - return True - return False - res = super(node_calendar_collection, self).match_dav_eprop(cr, match, ns, prop) - return res + - def get_dav_eprop(self,cr, ns, propname): + def get_dav_eprop(self,cr, ns, propname): if self.M_NS.has_key(ns): prefix = self.M_NS[ns] else: @@ -101,88 +87,27 @@ class node_calendar_collection(nodes.node_dir): return None def _file_get(self,cr, nodename=False): - return [] + return [] - def set_data(self, cr, data, fil_obj = None): - res = None - uid = self.context.uid - calendar_obj = self.context._dirobj.pool.get('basic.calendar') - if self.headers and self.headers.has_key('If-Match'): - for match in self.headers['If-Match'].split(','): - if match != '*': - tem, dav_time = tuple(match.split(':')) - title, cal_id, model, res_id = tuple(tem.split('-')) - res = calendar_obj.import_cal(cr, uid, base64.encodestring(data), cal_id) - - return res + + - - 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] - caluri, res_id = tuple(caluri.split('_')) - calendar = calendar_obj.name_search(cr, uid, caluri) - if calendar: - calendar_id, calendar_name = calendar[0] - if calendar_id not in ids: ids.append(calendar_id) - return [('id', 'in', ids)] - return res - - def _child_get(self, cr, name=False, parent_id=False, domain=None): + def _child_get(self, cr, name=False, parent_id=False, domain=None): dirobj = self.context._dirobj uid = self.context.uid ctx = self.context.context.copy() ctx.update(self.dctx) where = [('collection_id','=',self.dir_id)] - if name: - name, res_id = tuple(name.split('_')) - ctx.update({'res_id':res_id}) + if name: 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 = fil_obj.get_calendar_object(cr, uid, ids, parent=self, context=ctx) + res = [] + for calender in fil_obj.browse(cr, uid, ids, context=ctx): + res.append(node_calendar(calender.name, self, self.context, calender)) return res def _get_dav_owner(self, cr): @@ -210,7 +135,193 @@ class node_calendar_collection(nodes.node_dir): return str(result) -class node_calendar(nodes.node_class): +class node_calendar(nodes.node_class): + our_type = 'collection' + 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 = { + "DAV:" : '_get_dav', + "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 = 'application/x-directory' + self.create_date = calendar.create_date + self.write_date = calendar.write_date or calendar.create_date + self.content_length = 0 + self.displayname = calendar.name + self.cal_type = calendar.type + + def _get_dav_getctag(self, cr): + result = self.get_etag(cr) + return str(result) + + def match_dav_eprop(self, cr, match, ns, prop): + if ns == "DAV:" and prop == "getetag": + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + tem, dav_time = tuple(match.split(':')) + model, res_id = tuple(tem.split('_')) + model_obj = dirobj.pool.get(model) + model = model_obj.browse(cr, uid, res_id, context=ctx) + write_time = model.write_date or model.create_date + wtime = time.mktime(time.strptime(write_time,'%Y-%m-%d %H:%M:%S')) + if dav_time <= wtime: + return True + return False + res = super(node_calendar, self).match_dav_eprop(cr, match, ns, prop) + return res + + + 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': + names = [] + 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[-2] + if caluri not in names : names.append(caluri) + res = [('name','in',names)] + return res + return res + + def children(self, cr, domain=None): + return self._child_get(cr, domain=domain) + + 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=False, parent_id=False, domain=None): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + where = [] + if name: + where.append(('id','=',int(name))) + if not domain: + domain = [] + #for opr1, opt, opr2 in domain: + # if opr1 == 'type' and opr2 != self.cal_type: + # return [] + + fil_obj = dirobj.pool.get('basic.calendar') + ids = fil_obj.search(cr, uid, domain) + res = [] + if self.calendar_id in ids: + res = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx) + return res + + + + 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 create_child(self,cr,path,data): + """ API function to create a child file object and node + Return the node_* created + """ + return self.set_data(cr, data) + + + 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_data_len(self, cr, fil_obj = None): + return self.content_length + + + def _get_ttag(self,cr): + return 'calendar-%d' % (self.calendar_id,) + + + + def get_etag(self, cr): + """ Get a tag, unique per object + modification. + + see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """ + return self._get_ttag(cr) + ':' + self._get_wtag(cr) + + def _get_wtag(self, cr): + """ Return the modification time as a unique, compact string """ + 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) + + +class res_node_calendar(nodes.node_class): our_type = 'file' PROPS = { "http://calendarserver.org/ns/" : ('getctag'), @@ -225,23 +336,27 @@ class node_calendar(nodes.node_class): "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 + def __init__(self,path, parent, context, res_obj, res_model, res_id=None): + super(res_node_calendar,self).__init__(path, parent, context) + self.calendar_id = parent.calendar_id self.mimetype = 'text/calendar' - self.create_date = calendar.create_date - self.write_date = calendar.write_date or calendar.create_date + self.create_date = parent.create_date + self.write_date = parent.write_date or parent.create_date + if res_obj: + self.create_date = res_obj.create_date + self.write_date = res_obj.write_date or res_obj.create_date + self.displayname = res_obj.name + self.content_length = 0 - self.displayname = calendar.name - self.model = False - self.res_id = False + + self.model = res_model + self.res_id = res_id 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)) + return False + s = StringIO.StringIO(self.get_data(cr)) s.name = self return s @@ -288,7 +403,7 @@ class node_calendar(nodes.node_class): return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) def _get_ttag(self,cr): - return 'calendar-%d-%s-%d' % (self.calendar_id, self.model, self.res_id) + return '%s_%d' % (self.model, self.res_id) @@ -370,5 +485,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/calendar.py b/addons/caldav/calendar.py index d657cc4e619..3e4701a08d5 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -31,7 +31,7 @@ import pytz import re import tools import time -from caldav_node import node_calendar +from caldav_node import res_node_calendar try: import vobject @@ -258,7 +258,7 @@ class CalDAV(object): if not datas: return timezones = [] - for data in datas: + for data in datas: tzval = None vevent = ical.add(name) for field in self.__attribute__.keys(): @@ -438,9 +438,11 @@ class Calendar(CalDAV, osv.osv): 'write_date': fields.datetime('Modifided Date'), } - def get_calendar_object(self, cr, uid, ids, parent=None, context=None): + def get_calendar_objects(self, cr, uid, ids, parent=None, domain=None, context=None): if not context: context = {} + if not domain: + domain = [] res = [] ctx_res_id = context.get('res_id', None) ctx_model = context.get('model', None) @@ -450,16 +452,15 @@ class Calendar(CalDAV, osv.osv): continue if line.name in ('valarm', 'attendee'): continue - domain = eval(line.domain) + line_domain = eval(line.domain) + line_domain += domain if ctx_res_id: - domain += [('id','=',ctx_res_id)] + line_domain += [('id','=',ctx_res_id)] mod_obj = self.pool.get(line.object_id.model) - data_ids = mod_obj.search(cr, uid, domain, context=context) - for data_id in data_ids: + data_ids = mod_obj.search(cr, uid, line_domain, context=context) + for data in mod_obj.browse(cr, uid, data_ids, context): ctx = parent and parent.context or None - node = node_calendar('%s_%s' %(cal.name, data_id), parent, ctx, cal) - node.model = line.object_id.model - node.res_id = data_id + node = res_node_calendar('%s' %data.id, parent, ctx, data, line.object_id.model, data.id) res.append(node) return res @@ -510,12 +511,11 @@ class Calendar(CalDAV, osv.osv): ical_data = base64.decodestring(content) parsedCal = vobject.readOne(ical_data) if not data_id: - data_id = self.search(cr, uid, [])[0] - - cal = self.read(cr, uid, data_id, context=context)[0] + data_id = self.search(cr, uid, [])[0] + cal = self.browse(cr, uid, data_id, context=context) cal_children = {} count = 0 - for line in self.pool.get('basic.calendar.lines').browse(cr, uid, cal['line_ids']): + for line in cal.line_ids: cal_children[line.name] = line.object_id.model for child in parsedCal.getChildren(): if child.name.lower() in cal_children: diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index d8e654728e2..bfe9729a194 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -404,7 +404,7 @@ class openerp_dav_handler(dav_interface): node = self.uri2object(cr,uid,pool, uri2[:]) except: node = False - node.headers = self.parent.headers + objname = uri2[-1] ext = objname.find('.') >0 and objname.split('.')[1] or False diff --git a/addons/project_caldav/project_caldav.py b/addons/project_caldav/project_caldav.py index 6757861c3c5..62e18784887 100644 --- a/addons/project_caldav/project_caldav.py +++ b/addons/project_caldav/project_caldav.py @@ -26,6 +26,8 @@ class project_task(osv.osv): _name = "project.task" _inherit = ["calendar.todo", "project.task"] _columns = { + 'write_date' : fields.datetime('Write Date'), + 'create_date' : fields.datetime('Create Date'), 'attendee_ids': fields.many2many('calendar.attendee', \ 'task_attendee_rel', 'task_id', 'attendee_id', 'Attendees'), }