summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry (Open ERP) <hmo@tinyerp.com>2010-04-21 19:04:02 +0530
committerHarry (Open ERP) <hmo@tinyerp.com>2010-04-21 19:04:02 +0530
commit5c3cf27f2fa72cd64c54e6241f10b86a089d357a (patch)
treec6b2b469dfd1b4063b058316f367839eb4b9a208
parent96ce0830ced03ea5080cc05214900e747c7b584c (diff)
[IMP] caldav
bzr revid: hmo@tinyerp.com-20100421133402-191nwwj3nohx6zas
-rw-r--r--addons/caldav/caldav_node.py62
-rw-r--r--addons/caldav/calendar.py90
-rw-r--r--addons/document/nodes.py10
-rw-r--r--addons/document_webdav/dav_fs.py19
-rw-r--r--addons/document_webdav/webdav_server.py82
5 files changed, 210 insertions, 53 deletions
diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py
index d747078081d..81135751464 100644
--- a/addons/caldav/caldav_node.py
+++ b/addons/caldav/caldav_node.py
@@ -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):
diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py
index 58a51c11c85..d657cc4e619 100644
--- a/addons/caldav/calendar.py
+++ b/addons/caldav/calendar.py
@@ -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 export_cal(self, cr, uid, ids, vobj='vevent', context={}):
+ }
+
+ 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=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)
diff --git a/addons/document/nodes.py b/addons/document/nodes.py
index 26f6671f218..e74389dd0d4 100644
--- a/addons/document/nodes.py
+++ b/addons/document/nodes.py
@@ -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
diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py
index d8b369b5ecf..d8e654728e2 100644
--- a/addons/document_webdav/dav_fs.py
+++ b/addons/document_webdav/dav_fs.py
@@ -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
diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py
index 6cda2d172ef..5f88f90cf11 100644
--- a/addons/document_webdav/webdav_server.py
+++ b/addons/document_webdav/webdav_server.py
@@ -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