[IMP] caldav
bzr revid: hmo@tinyerp.com-20100421133402-191nwwj3nohx6zas
This commit is contained in:
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user