[IMP] caldav

bzr revid: hmo@tinyerp.com-20100421133402-191nwwj3nohx6zas
This commit is contained in:
Harry (Open ERP)
2010-04-21 19:04:02 +05:30
parent 96ce0830ce
commit 5c3cf27f2f
5 changed files with 208 additions and 51 deletions
+48 -14
View File
@@ -58,11 +58,28 @@ 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 get_dav_eprop(self,cr, ns, propname):
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):
if self.M_NS.has_key(ns):
prefix = self.M_NS[ns]
else:
@@ -86,6 +103,19 @@ class node_calendar_collection(nodes.node_dir):
def _file_get(self,cr, nodename=False):
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 = []
@@ -129,10 +159,11 @@ class node_calendar_collection(nodes.node_dir):
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]
ids.append(calendar_id)
if calendar_id not in ids: ids.append(calendar_id)
return [('id', 'in', ids)]
return res
@@ -143,16 +174,15 @@ class node_calendar_collection(nodes.node_dir):
ctx.update(self.dctx)
where = [('collection_id','=',self.dir_id)]
if name:
name, res_id = tuple(name.split('_'))
ctx.update({'res_id':res_id})
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 = []
if ids:
for fil in fil_obj.browse(cr,uid,ids,context=ctx):
res.append(node_calendar(fil.name,self,self.context,fil))
res = fil_obj.get_calendar_object(cr, uid, ids, parent=self, context=ctx)
return res
def _get_dav_owner(self, cr):
@@ -198,11 +228,13 @@ class node_calendar(nodes.node_class):
def __init__(self,path, parent, context, calendar):
super(node_calendar,self).__init__(path, parent,context)
self.calendar_id = calendar.id
self.mimetype = 'ics'
self.mimetype = 'text/calendar'
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.displayname = calendar.name
self.model = False
self.res_id = False
def open(self, cr, mode=False):
uid = self.context.uid
@@ -218,7 +250,7 @@ class node_calendar(nodes.node_class):
def get_dav_props(self, cr):
return self.PROPS
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:
@@ -239,10 +271,12 @@ class node_calendar(nodes.node_class):
return None
def get_data(self, cr, fil_obj = None):
def get_data(self, cr, fil_obj = None):
uid = self.context.uid
calendar_obj = self.context._dirobj.pool.get('basic.calendar')
res = calendar_obj.export_cal(cr, uid, [self.calendar_id])
context = self.context.context.copy()
context.update({'model': self.model, 'res_id':self.res_id})
res = calendar_obj.export_cal(cr, uid, [self.calendar_id], context=context)
return res
def get_data_len(self, cr, fil_obj = None):
@@ -254,7 +288,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' % self.calendar_id
return 'calendar-%d-%s-%d' % (self.calendar_id, self.model, self.res_id)
@@ -322,7 +356,7 @@ class node_calendar(nodes.node_class):
def _get_caldav_schedule_outbox_URL(self, cr):
return _get_caldav_schedule_inbox_URL(cr)
return self._get_caldav_schedule_inbox_URL(cr)
def get_etag(self, cr):
+54 -32
View File
@@ -31,6 +31,7 @@ import pytz
import re
import tools
import time
from caldav_node import node_calendar
try:
import vobject
@@ -435,22 +436,34 @@ class Calendar(CalDAV, osv.osv):
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
'create_date': fields.datetime('Created Date'),
'write_date': fields.datetime('Modifided Date'),
}
}
def get_calendar_object(self, cr, uid, uri, context=None):
if not uri:
return None
if len(uri) > 1:
return None
name, file_type = tuple(uri[0].split('.'))
res = self.name_search(cr, uid, name)
if not res:
return None
calendar_id, calendar_name = res[0]
calendar = self.browse(cr, uid, calendar_id)
return node_calendar(uri, context, calendar)
def get_calendar_object(self, cr, uid, ids, parent=None, context=None):
if not context:
context = {}
res = []
ctx_res_id = context.get('res_id', None)
ctx_model = context.get('model', None)
for cal in self.browse(cr, uid, ids):
for line in cal.line_ids:
if ctx_model and ctx_model != line.object_id.model:
continue
if line.name in ('valarm', 'attendee'):
continue
domain = eval(line.domain)
if ctx_res_id:
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:
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
res.append(node)
return res
def export_cal(self, cr, uid, ids, vobj='vevent', context={}):
def export_cal(self, cr, uid, ids, vobj='vevent', context=None):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@@ -458,20 +471,28 @@ class Calendar(CalDAV, osv.osv):
@param ids: List of calendar’s IDs
@param context: A standard dictionary for contextual values
"""
cal = self.browse(cr, uid, ids[0])
if not context:
context = {}
ctx_model = context.get('model', None)
ctx_res_id = context.get('res_id', None)
ical = vobject.iCalendar()
for line in cal.line_ids:
if line.name in ('valarm', 'attendee'):
continue
mod_obj = self.pool.get(line.object_id.model)
data_ids = mod_obj.search(cr, uid, eval(line.domain), context=context)
datas = mod_obj.read(cr, uid, data_ids, context=context)
context.update({'model': line.object_id.model,
'calendar_id': cal.id
})
self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context)
self.create_ics(cr, uid, datas, line.name, ical, context=context)
for cal in self.browse(cr, uid, ids):
for line in cal.line_ids:
if ctx_model and ctx_model != line.object_id.model:
continue
if line.name in ('valarm', 'attendee'):
continue
domain = eval(line.domain)
if ctx_res_id:
domain += [('id','=',ctx_res_id)]
mod_obj = self.pool.get(line.object_id.model)
data_ids = mod_obj.search(cr, uid, domain, context=context)
datas = mod_obj.read(cr, uid, data_ids, context=context)
context.update({'model': line.object_id.model,
'calendar_id': cal.id
})
self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context)
self.create_ics(cr, uid, datas, line.name, ical, context=context)
return ical.serialize()
def import_cal(self, cr, uid, content, data_id=None, context=None):
@@ -485,20 +506,21 @@ class Calendar(CalDAV, osv.osv):
if not context:
context = {}
vals = []
vals = []
ical_data = base64.decodestring(content)
parsedCal = vobject.readOne(ical_data)
if not data_id:
data_id = self.search(cr, uid, [])[0]
cal = self.browse(cr, uid, data_id)
data_id = self.search(cr, uid, [])[0]
cal = self.read(cr, uid, data_id, context=context)[0]
cal_children = {}
count = 0
for line in cal.line_ids:
for line in self.pool.get('basic.calendar.lines').browse(cr, uid, cal['line_ids']):
cal_children[line.name] = line.object_id.model
for child in parsedCal.getChildren():
if child.name.lower() in cal_children:
context.update({'model': cal_children[child.name.lower()],
'calendar_id': cal.id
'calendar_id': cal['id']
})
self.__attribute__ = get_attribute_mapping(cr, uid, child.name.lower(), context=context)
val = self.parse_ics(cr, uid, child, cal_children=cal_children, context=context)
+8 -2
View File
@@ -152,6 +152,12 @@ class node_class(object):
its capabilities """
return {}
def match_dav_eprop(self, cr, match, ns, prop):
res = self.get_dav_eprop(cr, ns, prop)
if res == match:
return True
return False
def get_dav_eprop(self,cr,ns,prop):
return None
@@ -259,8 +265,8 @@ class node_dir(node_database):
def get_data(self,cr):
res = ''
for child in self.children(cr):
res += child.get_data(cr)
for child in self.children(cr):
res += child.get_data(cr)
return res
+17 -2
View File
@@ -82,6 +82,20 @@ class openerp_dav_handler(dav_interface):
def _get_dav_supportedlock(self, uri):
raise DAV_NotFound
def match_prop(self, uri, match, ns, propname):
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
raise DAV_NotFound
node = self.uri2object(cr, uid, pool, uri2)
if not node:
cr.close()
raise DAV_NotFound
res = node.match_dav_eprop(cr, match, ns, propname)
cr.close()
return res
def get_prop(self, uri, ns, propname):
""" return the value of a given property
@@ -209,14 +223,14 @@ class openerp_dav_handler(dav_interface):
return None
return pool.get('document.directory').get_object(cr, uid, uri)
def get_data(self,uri):
def get_data(self,uri):
self.parent.log_message('GET: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
try:
if not dbname:
raise DAV_Error, 409
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr,uid,pool, uri2)
if not node:
raise DAV_NotFound(uri2)
try:
@@ -390,6 +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
+81 -1
View File
@@ -33,7 +33,10 @@ from dav_fs import openerp_dav_handler
from tools.config import config
from DAV.WebDAVServer import DAVRequestHandler
from service.websrv_lib import HTTPDir,FixSendError
import urlparse
import urllib
from string import atoi,split
from DAV.errors import *
def OpenDAVConfig(**kw):
class OpenDAV:
@@ -81,6 +84,83 @@ class DAVHandler(FixSendError,DAVRequestHandler):
def log_error(self, format, *args):
netsvc.Logger().notifyChannel('xmlrpc',netsvc.LOG_WARNING,format % args)
def do_PUT(self):
dc=self.IFACE_CLASS
uri=urlparse.urljoin(self.get_baseuri(dc), self.path)
uri=urllib.unquote(uri)
# Handle If-Match
if self.headers.has_key('If-Match'):
test = False
etag = None
for match in self.headers['If-Match'].split(','):
if match == '*':
if dc.exists(uri):
test = True
break
else:
if dc.match_prop(uri, match, "DAV:", "getetag"):
test = True
break
if not test:
self.send_status(412)
return
# Handle If-None-Match
if self.headers.has_key('If-None-Match'):
test = True
etag = None
for match in self.headers['If-None-Match'].split(','):
if match == '*':
if dc.exists(uri):
test = False
break
else:
if dc.match_prop(uri, match, "DAV:", "getetag"):
test = False
break
if not test:
self.send_status(412)
return
# Handle expect
expect = self.headers.get('Expect', '')
if (expect.lower() == '100-continue' and
self.protocol_version >= 'HTTP/1.1' and
self.request_version >= 'HTTP/1.1'):
self.send_status(100)
self._flush()
# read the body
body=None
if self.headers.has_key("Content-Length"):
l=self.headers['Content-Length']
body=self.rfile.read(atoi(l))
# locked resources are not allowed to be overwritten
if self._l_isLocked(uri):
return self.send_body(None, '423', 'Locked', 'Locked')
ct=None
if self.headers.has_key("Content-Type"):
ct=self.headers['Content-Type']
try:
location = dc.put(uri,body,ct)
except DAV_Error, (ec,dd):
return self.send_status(ec)
headers = {}
if location:
headers['Location'] = location
try:
etag = dc.get_prop(location or uri, "DAV:", "getetag")
headers['ETag'] = etag
except:
pass
self.send_body(None, '201', 'Created', '', headers=headers)
try:
from service.http_server import reg_http_service,OpenERPAuthProvider