diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index 241a36b1051..27b68003aa2 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -1500,6 +1500,7 @@ true, it will allow you to hide the event alarm information without removing it.
@param context: A standard dictionary for contextual values
@return: List of Dictionary of form [{‘name_of_the_field’: value, ...}, ...]
"""
+ # FIXME This whole id mangling has to go!
if not context:
context = {}
diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py
index f760421dfe5..3aa5dfd14dc 100644
--- a/addons/caldav/caldav.py
+++ b/addons/caldav/caldav.py
@@ -26,15 +26,16 @@ 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):
- res = super_mk_prop_response(self, uri,good_props,bad_props,doc)
- uris = uri.split('/')
- calendar = False
+
+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('/')
+ 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')
+ ad.setAttribute('xmlns', 'urn:ietf:params:xml:ns:caldav')
cols = res.getElementsByTagName('D:collection')
if cols:
cols[0].parentNode.appendChild(ad)
diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml
index e2ae6624979..2394c95d272 100644
--- a/addons/caldav/caldav_data.xml
+++ b/addons/caldav/caldav_data.xml
@@ -1,385 +1,390 @@
-
+
Calendars
True
-
+
-
+
- organizer
- vevent
-
-
-
- uid
- vevent
-
-
-
- seq
- vevent
-
-
-
- recurrence-id
- vevent
-
-
-
- transp
- vevent
-
-
-
- attendee
- vevent
-
-
-
- related
- vevent
-
-
-
- rrule
- vevent
-
-
-
- dtend
- vevent
-
-
-
- valarm
- vevent
-
-
-
- vtimezone
- vevent
-
-
-
- priority
- vevent
-
-
-
- location
- vevent
-
-
-
- exrule
- vevent
-
-
-
- resources
- vevent
-
-
-
- rstatus
- vevent
-
-
-
- status
- vevent
-
-
-
- exdate
- vevent
-
-
-
- dtstamp
- vevent
-
-
-
- description
- vevent
-
-
-
- rdate
- vevent
-
-
-
- dtstart
- vevent
-
-
-
- class
- vevent
-
-
-
- x-openobject-model
- vevent
-
-
-
- created
- vevent
-
-
-
- url
- vevent
-
-
-
- summary
- vevent
-
-
-
- contact
- vevent
-
-
-
-
-
-
- status
- vtodo
-
-
-
-
-
- attendee
- vtodo
-
-
-
- valarm
- vtodo
-
-
-
- description
- vtodo
-
-
-
- seq
- vtodo
-
-
-
- vtimezone
- vtodo
-
-
-
- url
- vtodo
-
-
-
- completed
- vtodo
-
-
-
- percent
- vtodo
-
-
-
- due
- vtodo
-
-
-
- summary
- vtodo
-
-
-
- priority
- vtodo
-
-
-
- exdate
- vtodo
-
-
-
- location
- vtodo
-
-
-
- exrule
- vtodo
-
-
-
- duration
- vtodo
-
-
-
- organizer
- vtodo
-
-
-
- dtstart
- vtodo
-
-
-
- rrule
- vtodo
-
-
-
- class
- vtodo
-
-
-
- uid
- vtodo
-
-
-
-
-
- cn
- attendee
-
-
-
- sent-by
- attendee
-
-
-
- language
- attendee
-
-
-
- delegated-from
- attendee
-
-
-
- member
- attendee
-
-
-
- cutype
- attendee
-
-
-
- role
- attendee
-
-
-
- partstat
- attendee
-
-
-
- delegated-to
- attendee
-
-
-
- dir
- attendee
-
-
-
- rsvp
- attendee
-
-
-
-
-
- attendee
- alarm
-
-
-
- trigger_duration
- alarm
-
-
-
- description
- alarm
-
-
-
- attach
- alarm
-
-
-
- trigger_occurs
- alarm
-
-
-
- trigger_interval
- alarm
-
-
-
- summary
- alarm
-
-
-
- duration
- alarm
-
-
-
- repeat
- alarm
-
-
-
- action
- alarm
-
-
-
- trigger_related
- alarm
-
-
-
+ organizer
+ vevent
+
+
+
+ uid
+ vevent
+
+
+
+ seq
+ vevent
+
+
+
+ recurrence-id
+ vevent
+
+
+
+ transp
+ vevent
+
+
+
+ attendee
+ vevent
+
+
+
+ related
+ vevent
+
+
+
+ rrule
+ vevent
+
+
+
+ dtend
+ vevent
+
+
+
+ duration
+ vevent
+
+
+
+ valarm
+ vevent
+
+
+
+ vtimezone
+ vevent
+
+
+
+ priority
+ vevent
+
+
+
+ location
+ vevent
+
+
+
+ exrule
+ vevent
+
+
+
+ resources
+ vevent
+
+
+
+ rstatus
+ vevent
+
+
+
+ status
+ vevent
+
+
+
+ exdate
+ vevent
+
+
+
+ dtstamp
+ vevent
+
+
+
+ description
+ vevent
+
+
+
+ rdate
+ vevent
+
+
+
+ dtstart
+ vevent
+
+
+
+ class
+ vevent
+
+
+
+ x-openobject-model
+ vevent
+
+
+
+ created
+ vevent
+
+
+
+ url
+ vevent
+
+
+
+ summary
+ vevent
+
+
+
+ contact
+ vevent
+
+
+
+
+
+
+ status
+ vtodo
+
+
+
+
+
+ attendee
+ vtodo
+
+
+
+ valarm
+ vtodo
+
+
+
+ description
+ vtodo
+
+
+
+ sequence
+ vtodo
+
+
+
+ vtimezone
+ vtodo
+
+
+
+ url
+ vtodo
+
+
+
+ completed
+ vtodo
+
+
+
+ percent-complete
+ vtodo
+
+
+
+ due
+ vtodo
+
+
+
+ summary
+ vtodo
+
+
+
+ priority
+ vtodo
+
+
+
+ exdate
+ vtodo
+
+
+
+ location
+ vtodo
+
+
+
+ exrule
+ vtodo
+
+
+
+ duration
+ vtodo
+
+
+
+ organizer
+ vtodo
+
+
+
+ dtstart
+ vtodo
+
+
+
+ rrule
+ vtodo
+
+
+
+ class
+ vtodo
+
+
+
+ uid
+ vtodo
+
+
+
+
+
+ cn
+ attendee
+
+
+
+ sent-by
+ attendee
+
+
+
+ language
+ attendee
+
+
+
+ delegated-from
+ attendee
+
+
+
+ member
+ attendee
+
+
+
+ cutype
+ attendee
+
+
+
+ role
+ attendee
+
+
+
+ partstat
+ attendee
+
+
+
+ delegated-to
+ attendee
+
+
+
+ dir
+ attendee
+
+
+
+ rsvp
+ attendee
+
+
+
+
+
+ attendee
+ alarm
+
+
+
+ trigger_duration
+ alarm
+
+
+
+ description
+ alarm
+
+
+
+ attach
+ alarm
+
+
+
+ trigger_occurs
+ alarm
+
+
+
+ trigger_interval
+ alarm
+
+
+
+ summary
+ alarm
+
+
+
+ duration
+ alarm
+
+
+
+ repeat
+ alarm
+
+
+
+ action
+ alarm
+
+
+
+ trigger_related
+ alarm
+
+
+
diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py
index 8ec7422a045..3ae37ea3e7e 100644
--- a/addons/caldav/caldav_node.py
+++ b/addons/caldav/caldav_node.py
@@ -24,7 +24,6 @@ from tools.translate import _
import pooler
import tools
import time
-import base64
from document import nodes
import StringIO
@@ -38,78 +37,48 @@ class node_database(nodes.node_database):
domain = []
domain2 = domain + [('calendar_collection','=', False)]
res = super(node_database, self)._child_get(cr, name=name, parent_id=parent_id, domain=domain2)
- where = [('parent_id','=',parent_id)]
- domain2 = domain + [('calendar_collection','=', True)]
+ where = [('parent_id','=',parent_id)]
+ domain2 = domain + [('calendar_collection','=', True)]
if name:
where.append(('name','=',name))
if domain2:
where += domain2
where2 = where + [('type', '=', 'directory')]
- ids = dirobj.search(cr, uid, where2, context=ctx)
- for dirr in dirobj.browse(cr,uid,ids,context=ctx):
+ ids = dirobj.search(cr, uid, where2, context=ctx)
+ for dirr in dirobj.browse(cr,uid,ids,context=ctx):
res.append(node_calendar_collection(dirr.name,self,self.context,dirr))
return res
-class node_calendar_collection(nodes.node_dir):
- PROPS = {
- "http://calendarserver.org/ns/" : ('getctag'),
- }
- M_NS = {
+class node_calendar_collection(nodes.node_dir):
+ DAV_PROPS = {
+ "http://calendarserver.org/ns/" : ('getctag',),
+ }
+ DAV_M_NS = {
"http://calendarserver.org/ns/" : '_get_dav',
- }
+ }
-
- 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
-
- 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
+ http_options = { 'DAV': ['calendar-access'] }
def _file_get(self,cr, nodename=False):
return []
-
-
-
- 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)]
- ext = False
- if name:
- res = name.split('.ics')
- if len(res) > 1:
- name = res[0]
- ext = '.ics'
- if name:
+ where = [('collection_id','=',self.dir_id)]
+ ext = False
+ if name and name.endswith('.ics'):
+ name = name[-4]
+ ext = '.ics'
+ if name:
where.append(('name','=',name))
if not domain:
- domain = []
+ domain = []
where = where + domain
- fil_obj = dirobj.pool.get('basic.calendar')
+ fil_obj = dirobj.pool.get('basic.calendar')
ids = fil_obj.search(cr,uid,where,context=ctx)
res = []
for calender in fil_obj.browse(cr, uid, ids, context=ctx):
@@ -120,34 +89,21 @@ class node_calendar_collection(nodes.node_dir):
return res
def _get_dav_owner(self, cr):
+ # Todo?
return False
-
- 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)
-
def _get_ttag(self, cr):
- return 'calendar collection-%d' % self.dir_id
+ return 'calen-dir-%d' % self.dir_id
def _get_dav_getctag(self, cr):
- result = self.get_etag(cr)
- return str(result)
-
+ result = self.get_etag(cr)
+ return str(result)
-class node_calendar(nodes.node_class):
- our_type = 'collection'
- PROPS = {
- "http://calendarserver.org/ns/" : ('getctag'),
+class node_calendar(nodes.node_class):
+ our_type = 'collection'
+ DAV_PROPS = {
+ "http://calendarserver.org/ns/" : ('getctag',),
+ 'http://groupdav.org/': ('resourcetype',),
"urn:ietf:params:xml:ns:caldav" : (
'calendar-description',
'calendar-data',
@@ -155,10 +111,13 @@ class node_calendar(nodes.node_class):
'calendar-user-address-set',
'schedule-inbox-URL',
'schedule-outbox-URL',)}
- M_NS = {
- "DAV:" : '_get_dav',
+ DAV_M_NS = {
+ "DAV:" : '_get_dav',
+ 'http://groupdav.org/': '_get_gdav',
"http://calendarserver.org/ns/" : '_get_dav',
- "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
+ "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
+
+ http_options = { 'DAV': ['calendar-access'] }
def __init__(self,path, parent, context, calendar):
super(node_calendar,self).__init__(path, parent,context)
@@ -170,45 +129,49 @@ class node_calendar(nodes.node_class):
self.displayname = calendar.name
self.cal_type = calendar.type
- def _get_dav_getctag(self, cr):
+ def _get_dav_getctag(self, cr):
result = self._get_ttag(cr) + ':' + str(time.time())
- return str(result)
+ return str(result)
- def match_dav_eprop(self, cr, match, ns, prop):
+ def _get_gdav_resourcetype(self, cr):
+ return (str(self.cal_type + '-collection'), 'http://groupdav.org/')
+
+ def removeme_match_dav_eprop(self, cr, match, ns, prop):
+ # Why?
if ns == "DAV:" and prop == "getetag":
dirobj = self.context._dirobj
uid = self.context.uid
- ctx = self.context.context.copy()
+ 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'))
+ wtime = time.mktime(time.strptime(write_time,'%Y-%m-%d %H:%M:%S'))
if float(dav_time) == float(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):
+ return res
+
+ def get_domain(self, cr, filters):
+ # TODO: doc.
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')
+ # 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':
+ 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':
+ continue
+ if filter_child.localName == 'filter':
for vcalendar_filter in filter_child.childNodes:
- if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE:
+ if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE:
continue
if vcalendar_filter.localName == 'comp-filter':
if vcalendar_filter.getAttribute('name') == 'VCALENDAR':
@@ -216,10 +179,10 @@ class node_calendar(nodes.node_class):
if vevent_filter.nodeType == vevent_filter.TEXT_NODE:
continue
if vevent_filter.localName == 'comp-filter':
- if vevent_filter.getAttribute('name') == 'VEVENT':
+ if vevent_filter.getAttribute('name') == 'VEVENT':
res = [('type','=','vevent')]
if vevent_filter.getAttribute('name') == 'VTODO':
- res = [('type','=','vtodo')]
+ res = [('type','=','vtodo')]
return res
elif filters.localName == 'calendar-multiget':
names = []
@@ -229,105 +192,70 @@ class node_calendar(nodes.node_class):
if filter_child.localName == 'href':
if not filter_child.firstChild:
continue
- uri = filter_child.firstChild.data
+ 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
+ return res
- def children(self, cr, domain=None):
+ 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)
+ def child(self,cr, name, domain=None):
+ res = self._child_get(cr, name, domain=domain)
if res:
return res[0]
- return None
+ 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)))
+ ctx.update(self.dctx)
+ where = []
+ if name:
+ if name.endswith('.ics'):
+ name = name[:-4]
+ 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')
+ 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
+ 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):
+ 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)
+ # we ignore the path, it will be re-generated automatically
+ res = self.set_data(cr, data)
+
+ # TODO: use the res to create at least one node
+ return None
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)
+ res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
+ return res
- def get_data_len(self, cr, fil_obj = None):
+ 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)
+ return 'calendar-%d' % (self.calendar_id,)
def rmcol(self, cr):
return False
@@ -335,7 +263,7 @@ class node_calendar(nodes.node_class):
class res_node_calendar(nodes.node_class):
our_type = 'file'
- PROPS = {
+ DAV_PROPS = {
"http://calendarserver.org/ns/" : ('getctag'),
"urn:ietf:params:xml:ns:caldav" : (
'calendar-description',
@@ -344,76 +272,54 @@ class res_node_calendar(nodes.node_class):
'calendar-user-address-set',
'schedule-inbox-URL',
'schedule-outbox-URL',)}
- M_NS = {
+ DAV_M_NS = {
"http://calendarserver.org/ns/" : '_get_dav',
- "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
+ "urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
+
+ http_options = { 'DAV': ['calendar-access'] }
def __init__(self,path, parent, context, res_obj, res_model=None, res_id=None):
- super(res_node_calendar,self).__init__(path, parent, context)
+ super(res_node_calendar,self).__init__(path, parent, context)
self.mimetype = 'text/calendar'
self.create_date = parent.create_date
self.write_date = parent.write_date or parent.create_date
self.calendar_id = hasattr(parent, 'calendar_id') and parent.calendar_id or False
if res_obj:
if not self.calendar_id: self.calendar_id = res_obj.id
- self.create_date = res_obj.create_date
- self.write_date = res_obj.write_date or res_obj.create_date
+ pr = res_obj.perm_read()[0]
+ self.create_date = pr.get('create_date')
+ self.write_date = pr.get('write_date') or pr.get('create_date')
self.displayname = res_obj.name
self.content_length = 0
-
+
self.model = res_model
self.res_id = res_id
-
+
def open(self, cr, mode=False):
- uid = self.context.uid
+ uid = self.context.uid
if self.type in ('collection','database'):
- return False
- s = StringIO.StringIO(self.get_data(cr))
+ return False
+ s = StringIO.StringIO(self.get_data(cr))
s.name = self
- return s
+ 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):
+ def get_data(self, cr, fil_obj = None):
uid = self.context.uid
calendar_obj = self.context._dirobj.pool.get('basic.calendar')
- 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)
+ 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):
+ 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)
+ res = calendar_obj.import_cal(cr, uid, data, self.calendar_id)
+ return res
def _get_ttag(self,cr):
res = False
@@ -423,30 +329,28 @@ class res_node_calendar(nodes.node_class):
res = '%d' % (self.calendar_id)
return res
-
-
- def _get_caldav_calendar_data(self, cr):
+ def _get_caldav_calendar_data(self, cr):
return self.get_data(cr)
-
+
def _get_caldav_calendar_description(self, cr):
uid = self.context.uid
calendar_obj = self.context._dirobj.pool.get('basic.calendar')
ctx = self.context.context.copy()
- ctx.update(self.dctx)
+ 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
+ import urllib
uid = self.context.uid
ctx = self.context.context.copy()
ctx.update(self.dctx)
- doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
-
- calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
+
+ 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
@@ -461,7 +365,7 @@ class res_node_calendar(nodes.node_class):
ctx = self.context.context.copy()
ctx.update(self.dctx)
user_obj = self.context._dirobj.pool.get('res.users')
- user = user_obj.browse(cr, uid, uid, context=ctx)
+ user = user_obj.browse(cr, uid, uid, context=ctx)
doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
href = doc.documentElement
href.tagName = 'D:href'
@@ -472,11 +376,11 @@ class res_node_calendar(nodes.node_class):
def _get_caldav_schedule_inbox_URL(self, cr):
import xml.dom.minidom
- import urllib
+ import urllib
uid = self.context.uid
ctx = self.context.context.copy()
ctx.update(self.dctx)
- calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ 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)
@@ -491,31 +395,15 @@ class res_node_calendar(nodes.node_class):
uid = self.context.uid
res = False
if self.type in ('collection','database'):
- return False
- if self.model and self.res_id:
+ return False
+ if self.model and self.res_id:
document_obj = self.context._dirobj.pool.get(self.model)
if document_obj:
- res = False
- #res = document_obj.unlink(cr, uid, [self.res_id]) #TOFIX
-
- return res
-
+ res = document_obj.unlink(cr, uid, [self.res_id])
+ return res
def _get_caldav_schedule_outbox_URL(self, cr):
return self._get_caldav_schedule_inbox_URL(cr)
-
- 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)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4
diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml
index d1cb79a0e4a..9184a0aadd2 100644
--- a/addons/caldav/caldav_view.xml
+++ b/addons/caldav/caldav_view.xml
@@ -1,6 +1,6 @@
-
+
Calendar Collections : Form
document.directory
@@ -17,10 +17,10 @@
Calendar Collections : Tree
document.directory
- tree
+ tree
-
+
@@ -73,34 +73,34 @@
-
+
-
+
-
-
-
+
+
+
@@ -110,11 +110,11 @@
Calendar : Tree
basic.calendar
- tree
+ tree
-
-
+
+
@@ -127,8 +127,8 @@
ir.actions.act_window
basic.calendar
form
- tree,form
-
+ tree,form
+
@@ -147,5 +147,5 @@
action="action_caldav_form"
id="menu_caldav_directories"
parent="menu_calendar"/>
-
+
diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py
index a45152501cc..c62055554ce 100644
--- a/addons/caldav/calendar.py
+++ b/addons/caldav/calendar.py
@@ -24,7 +24,6 @@ from dateutil import parser
from dateutil.rrule import *
from osv import osv, fields
from tools.translate import _
-import base64
import math
import pooler
import pytz
@@ -52,6 +51,8 @@ def uid2openobjectid(cr, uidval, oomodel, rdate):
@param rdate: Get Recurrent Date
"""
__rege = re.compile(r'OpenObject-([\w|\.]+)_([0-9]+)@(\w+)$')
+ if not uidval:
+ return (False, None)
wematch = __rege.match(uidval.encode('utf8'))
if not wematch:
return (False, None)
@@ -133,7 +134,7 @@ def map_data(cr, uid, obj, context=None):
continue
mapping = obj.__attribute__[map_dict].get('mapping', False)
if mapping:
- map_val = mapping[map_val.lower()]
+ map_val = mapping.get(map_val.lower(), False)
else:
map_val = map_val.lower()
if field_type == 'many2many':
@@ -381,7 +382,7 @@ class CalDAV(object):
raise osv.except_osv(('Error !'), (str(e)))
return ids
- def export_cal(self, cr, uid, datas, vobj=None, context={}):
+ def export_cal(self, cr, uid, datas, vobj=None, context=None):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@@ -396,7 +397,7 @@ class CalDAV(object):
self.create_ics(cr, uid, datas, vobj, ical, context=context)
return ical
except Exception, e:
- raise osv.except_osv(('Error !'), (str(e)))
+ raise # osv.except_osv(('Error !'), (str(e)))
def import_cal(self, cr, uid, content, data_id=None, context=None):
""" Import Calendar
@@ -407,7 +408,7 @@ class CalDAV(object):
@param context: A standard dictionary for contextual values
"""
- ical_data = base64.decodestring(content)
+ ical_data = content
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
parsedCal = vobject.readOne(ical_data)
res = []
@@ -447,8 +448,8 @@ class Calendar(CalDAV, osv.osv):
'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'),
+ 'create_date': fields.datetime('Created Date', readonly=True),
+ 'write_date': fields.datetime('Modifided Date', readonly=True),
}
def get_calendar_objects(self, cr, uid, ids, parent=None, domain=None, context=None):
@@ -473,17 +474,16 @@ class Calendar(CalDAV, osv.osv):
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 = res_node_calendar('%s' %data.id, parent, ctx, data, line.object_id.model, data.id)
+ node = res_node_calendar('%s.ics' %data.id, parent, ctx, data, line.object_id.model, 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,
- @param uid: the current user’s ID for security checks,
@param ids: List of calendar’s IDs
- @param context: A standard dictionary for contextual values
+ @param vobj: the type of object to export
+
+ @return the ical data.
"""
if not context:
context = {}
@@ -521,7 +521,7 @@ class Calendar(CalDAV, osv.osv):
if not context:
context = {}
vals = []
- ical_data = base64.decodestring(content)
+ ical_data = content
parsedCal = vobject.readOne(ical_data)
if not data_id:
data_id = self.search(cr, uid, [])[0]
@@ -541,14 +541,19 @@ class Calendar(CalDAV, osv.osv):
val = self.parse_ics(cr, uid, child, cal_children=cal_children, context=context)
vals.append(val)
objs.append(cal_children[child.name.lower()])
+
+ res = []
for obj_name in list(set(objs)):
obj = self.pool.get(obj_name)
if hasattr(obj, 'check_import'):
- obj.check_import(cr, uid, vals, context=context)
+ r = obj.check_import(cr, uid, vals, context=context)
checked = True
+ res.extend(r)
+
if not checked:
- self.check_import(cr, uid, vals, context=context)
- return {}
+ r = self.check_import(cr, uid, vals, context=context)
+ res.extend(r)
+ return res
Calendar()
@@ -632,6 +637,10 @@ class basic_calendar_fields(osv.osv):
'fn': lambda *a: 'field',
}
+ _sql_constraints = [
+ ( 'name_type_uniq', 'UNIQUE(name, type_id)', 'Can not map a field more than once'),
+ ]
+
def check_line(self, cr, uid, vals, name, context=None):
""" check calendar's line
@param self: The object pointer
@@ -667,12 +676,6 @@ class basic_calendar_fields(osv.osv):
name = name[0]
if name in ('valarm', 'attendee'):
self.check_line(cr, uid, vals, name, context=context)
- cr.execute("Select count(id) from basic_calendar_fields \
- where name=%s and type_id=%s" % (vals.get('name'), vals.get('type_id')))
- res = cr.fetchone()
- if res:
- if res[0] > 0:
- raise osv.except_osv(_('Warning !'), _('Can not map the field more than once'))
return super(basic_calendar_fields, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
@@ -691,13 +694,6 @@ class basic_calendar_fields(osv.osv):
name = field.name.name
if name in ('valarm', 'attendee'):
self.check_line(cr, uid, vals, name, context=context)
- qry = "Select count(id) from basic_calendar_fields \
- where name=%s and type_id=%s" % (field.name.id, field.type_id.id)
- cr.execute(qry)
- res = cr.fetchone()
- if res:
- if res[0] > 1:
- raise osv.except_osv(_('Warning !'), _('Can not map same field more than once'))
return super(basic_calendar_fields, self).write(cr, uid, ids, vals, context)
basic_calendar_fields()
diff --git a/addons/caldav/wizard/calendar_event_export_view.xml b/addons/caldav/wizard/calendar_event_export_view.xml
index cfadf945bf4..3161bb7d45e 100644
--- a/addons/caldav/wizard/calendar_event_export_view.xml
+++ b/addons/caldav/wizard/calendar_event_export_view.xml
@@ -1,25 +1,25 @@
-
+
calendar.event.export.form
calendar.event.export
form
-
-
-
+
+
+
-
+
-
-
+
+
-
-
+
+
Export .ics File
calendar.event.export
@@ -30,10 +30,10 @@
-
+
diff --git a/addons/caldav/wizard/calendar_event_import_view.xml b/addons/caldav/wizard/calendar_event_import_view.xml
index 7e31d08c1e9..41afcc7fcfd 100644
--- a/addons/caldav/wizard/calendar_event_import_view.xml
+++ b/addons/caldav/wizard/calendar_event_import_view.xml
@@ -1,42 +1,42 @@
-
+
calendar.event.import.form
calendar.event.import
form
-
-
-
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
calendar.event.import.form.display
calendar.event.import
form
-
-
+
+
-
+
-
+
-
-
+
+
Import .ics File
calendar.event.import
@@ -47,9 +47,9 @@
-
+ key2="client_action_multi" name="Import .ics File"
+ res_model="calendar.event.import" src_model="basic.calendar"
+ view_mode="form" target="new" view_type="form" />
+
diff --git a/addons/caldav/wizard/calendar_event_subscribe_view.xml b/addons/caldav/wizard/calendar_event_subscribe_view.xml
index 39eaae28540..563635368f4 100644
--- a/addons/caldav/wizard/calendar_event_subscribe_view.xml
+++ b/addons/caldav/wizard/calendar_event_subscribe_view.xml
@@ -1,42 +1,42 @@
-
+
calendar.event.subscribe.form
calendar.event.subscribe
form
-
-
-
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
calendar.event.subscribe.form.display
calendar.event.subscribe
form
-
-
+
+
-
+
-
+
-
-
+
+
Subscribe
calendar.event.subscribe
@@ -47,9 +47,9 @@
+ key2="client_action_multi" name="Subscribe"
+ res_model="calendar.event.subscribe" src_model="basic.calendar"
+ view_mode="form" target="new" view_type="form" />
diff --git a/addons/document/nodes.py b/addons/document/nodes.py
index f1ac35c333c..de2a83285f9 100644
--- a/addons/document/nodes.py
+++ b/addons/document/nodes.py
@@ -44,6 +44,20 @@ from StringIO import StringIO
# root: if we are at the first directory of a ressource
#
+def _str2time(cre):
+ """ Convert a string with time representation (from db) into time (float)
+
+ Note: a place to fix if datetime is used in db.
+ """
+ if not cre:
+ return time.time()
+ frac = 0.0
+ if isinstance(cre, basestring) and '.' in cre:
+ fdot = cre.find('.')
+ frac = float(cre[fdot:])
+ cre = cre[:fdot]
+ return time.mktime(time.strptime(cre,'%Y-%m-%d %H:%M:%S')) + frac
+
def get_node_context(cr, uid, context):
return node_context(cr, uid, context)
@@ -157,6 +171,8 @@ class node_class(object):
Nodes have attributes which contain usual file properties
"""
our_type = 'baseclass'
+ DAV_PROPS = None
+ DAV_M_NS = None
def __init__(self, path, parent, context):
assert isinstance(context,node_context)
@@ -253,24 +269,21 @@ class node_class(object):
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):
+ 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)
+ return str(_str2time(self.write_date))
def _get_ttag(self,cr):
""" Get a unique tag for this type/id of object.
Must be overriden, so that each node is uniquely identified.
"""
print "node_class.get_ttag()",self
- raise RuntimeError("get_etag stub()")
+ raise NotImplementedError("get_etag stub()")
def get_dav_props(self, cr):
""" If this class has special behaviour for GroupDAV etc, export
its capabilities """
- return {}
+ return self.DAV_PROPS or {}
def match_dav_eprop(self, cr, match, ns, prop):
res = self.get_dav_eprop(cr, ns, prop)
@@ -279,6 +292,26 @@ class node_class(object):
return False
def get_dav_eprop(self, cr, ns, prop):
+ if not self.DAV_M_NS:
+ return None
+
+ if self.DAV_M_NS.has_key(ns):
+ prefix = self.DAV_M_NS[ns]
+ else:
+ logger.debug('No namespace: %s ("%s")',ns, prop)
+ return None
+
+ mname = prefix + "_" + prop.replace('-','_')
+
+ if not hasattr(self, mname):
+ return None
+
+ try:
+ m = getattr(self, mname)
+ r = m(cr)
+ return r
+ except AttributeError:
+ logger.debug('Property %s not supported' % prop, exc_info=True)
return None
def move_to(self, cr, ndir_node, new_name=False, fil_obj=None, ndir_obj=None, in_write=False):
@@ -327,6 +360,7 @@ class node_class(object):
raise NotImplementedError(repr(self))
def get_domain(self, cr, filters):
+ # TODO Document
return []
def check_perms(self, perms):
@@ -573,19 +607,6 @@ class node_dir(node_database):
fnode.set_data(cr, data, fil)
return fnode
- 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)
-
def _get_ttag(self,cr):
return 'dir-%d' % self.dir_id
diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py
index ab9d3a75ae4..78812ff8cf5 100644
--- a/addons/document_webdav/dav_fs.py
+++ b/addons/document_webdav/dav_fs.py
@@ -46,6 +46,10 @@ CACHE_SIZE=20000
urlparse.uses_netloc.append('webdav')
urlparse.uses_netloc.append('webdavs')
+day_names = { 0: 'Mon', 1: 'Tue' , 2: 'Wed', 3: 'Thu', 4: 'Fri', 5: 'Sat', 6: 'Sun' }
+month_names = { 1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun',
+ 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec' }
+
class DAV_NotFound2(DAV_NotFound):
"""404 exception, that accepts our list uris
"""
@@ -55,6 +59,19 @@ class DAV_NotFound2(DAV_NotFound):
args = (path, )
DAV_NotFound.__init__(self, *args)
+
+def _str2time(cre):
+ """ Convert a string with time representation (from db) into time (float)
+ """
+ if not cre:
+ return time.time()
+ frac = 0.0
+ if isinstance(cre, basestring) and '.' in cre:
+ fdot = cre.find('.')
+ frac = float(cre[fdot:])
+ cre = cre[:fdot]
+ return time.mktime(time.strptime(cre,'%Y-%m-%d %H:%M:%S')) + frac
+
class openerp_dav_handler(dav_interface):
"""
This class models a OpenERP interface for the DAV server
@@ -79,20 +96,21 @@ class openerp_dav_handler(dav_interface):
return props
node = self.uri2object(cr, uid, pool, uri2)
if node:
+ props = props.copy()
props.update(node.get_dav_props(cr))
cr.close()
return props
- def _try_function(self, funct, args, opname='run function', cr=None,
- default_exc=DAV_Forbidden):
+ def _try_function(self, funct, args, opname='run function', cr=None,
+ default_exc=DAV_Forbidden):
""" Try to run a function, and properly convert exceptions to DAV ones.
-
+
@objname the name of the operation being performed
@param cr if given, the cursor to close at exceptions
"""
-
+
try:
- funct(*args)
+ return funct(*args)
except DAV_Error:
if cr: cr.close()
raise
@@ -111,7 +129,7 @@ class openerp_dav_handler(dav_interface):
raise default_exc(err.strerror)
except Exception,e:
import traceback
- self.parent.log_error("Cannot create %s: %s", opname, str(e))
+ self.parent.log_error("Cannot %s: %s", opname, str(e))
self.parent.log_message("Exc: %s",traceback.format_exc())
raise default_exc("Operation failed")
@@ -122,6 +140,8 @@ class openerp_dav_handler(dav_interface):
raise DAV_NotFound
def match_prop(self, uri, match, ns, propname):
+ if self.M_NS.has_key(ns):
+ return match == dav_interface.get_prop(self, uri, ns, propname)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
if cr: cr.close()
@@ -134,6 +154,37 @@ class openerp_dav_handler(dav_interface):
cr.close()
return res
+ def prep_http_options(self, uri, opts):
+ """see HttpOptions._prep_OPTIONS """
+ self.parent.log_message('get options: %s' % uri)
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True)
+
+ if not dbname:
+ if cr: cr.close()
+ return opts
+ node = self.uri2object(cr, uid, pool, uri2[:])
+
+ if not node:
+ if cr: cr.close()
+ return opts
+ else:
+ if hasattr(node, 'http_options'):
+ ret = opts.copy()
+ for key, val in node.http_options.items():
+ if isinstance(val, basestring):
+ val = [val, ]
+ if key in ret:
+ ret[key] = ret[key][:] # copy the orig. array
+ else:
+ ret[key] = []
+ ret[key].extend(val)
+
+ self.parent.log_message('options: %s' % ret)
+ else:
+ ret = opts
+ cr.close()
+ return ret
+
def get_prop(self, uri, ns, propname):
""" return the value of a given property
@@ -159,18 +210,18 @@ class openerp_dav_handler(dav_interface):
"""Parse the uri and get the dbname and the rest.
Db name should be the first component in the unix-like
path supplied in uri.
-
+
@param rest_ret Instead of the db_name, return (db_name, rest),
where rest is the remaining path
@param allow_last If the dbname is the last component in the
path, allow it to be resolved. The default False value means
we will not attempt to use the db, unless there is more
path.
-
+
@return db_name or (dbname, rest) depending on rest_ret,
will return dbname=False when component is not found.
"""
-
+
uri2 = self.uri2local(uri)
if uri2.startswith('/'):
uri2 = uri2[1:]
@@ -294,7 +345,7 @@ class openerp_dav_handler(dav_interface):
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_NotFound2(uri2)
try:
@@ -339,11 +390,11 @@ class openerp_dav_handler(dav_interface):
self.parent.log_message('get DN: %s' % uri)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
- cr.close()
+ if cr: cr.close()
return COLLECTION
node = self.uri2object(cr, uid, pool, uri2)
if not node:
- cr.close()
+ if cr: cr.close()
raise DAV_NotFound2(uri2)
cr.close()
return node.displayname
@@ -359,7 +410,7 @@ class openerp_dav_handler(dav_interface):
return str(result)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
- cr.close()
+ if cr: cr.close()
raise DAV_NotFound2(uri2)
result = node.content_length or 0
cr.close()
@@ -372,34 +423,41 @@ class openerp_dav_handler(dav_interface):
result = 0
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
- cr.close()
+ if cr: cr.close()
return '0'
node = self.uri2object(cr, uid, pool, uri2)
if not node:
cr.close()
raise DAV_NotFound2(uri2)
- result = node.get_etag(cr)
+ result = self._try_function(node.get_etag ,(cr,), "etag %s" %uri, cr=cr)
cr.close()
return str(result)
@memoize(CACHE_SIZE)
def get_lastmodified(self, uri):
""" return the last modified date of the object """
- today = time.time()
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
- return today
+ return time.time()
try:
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound2(uri2)
- if node.write_date:
- return time.mktime(time.strptime(node.write_date,'%Y-%m-%d %H:%M:%S'))
- else:
- return today
+ return _str2time(node.write_date)
finally:
if cr: cr.close()
+ def _get_dav_getlastmodified(self,uri):
+ """ return the last modified date of a resource
+ """
+ d=self.get_lastmodified(uri)
+ # format it. Note that we explicitly set the day, month names from
+ # an array, so that strftime() doesn't use its own locale-aware
+ # strings.
+ gmt = time.gmtime(d)
+ return time.strftime("%%s, %d %%s %Y %H:%M:%S GMT", gmt ) % \
+ (day_names[gmt.tm_wday], month_names[gmt.tm_mon])
+
@memoize(CACHE_SIZE)
def get_creationdate(self, uri):
""" return the last modified date of the object """
@@ -410,11 +468,8 @@ class openerp_dav_handler(dav_interface):
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound2(uri2)
- if node.create_date:
- result = time.mktime(time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S'))
- else:
- result = time.time()
- return result
+
+ return _str2time(node.create_date)
finally:
if cr: cr.close()
@@ -423,6 +478,7 @@ class openerp_dav_handler(dav_interface):
self.parent.log_message('get contenttype: %s' % uri)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
+ if cr: cr.close()
return 'httpd/unix-directory'
try:
node = self.uri2object(cr, uid, pool, uri2)
@@ -441,10 +497,10 @@ class openerp_dav_handler(dav_interface):
self.parent.log_message('MKCOL: %s' % uri)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not uri2[-1]:
- cr.close()
+ if cr: cr.close()
raise DAV_Error(409, "Cannot create nameless collection")
if not dbname:
- cr.close()
+ if cr: cr.close()
raise DAV_Error, 409
node = self.uri2object(cr,uid,pool, uri2[:-1])
if not node:
@@ -466,10 +522,11 @@ class openerp_dav_handler(dav_interface):
parent='/'.join(uri.split('/')[:-1])
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
if not dbname:
+ if cr: cr.close()
raise DAV_Forbidden
try:
node = self.uri2object(cr, uid, pool, uri2[:])
- except:
+ except Exception:
node = False
objname = uri2[-1]
@@ -481,7 +538,7 @@ class openerp_dav_handler(dav_interface):
cr.close()
raise DAV_NotFound('Parent folder not found')
- self._try_function(dir_node.create_child, (cr, objname, data),
+ self._try_function(dir_node.create_child, (cr, objname, data),
"create %s" % objname, cr=cr)
else:
self._try_function(node.set_data, (cr, data), "save %s" % objname, cr=cr)
@@ -494,9 +551,11 @@ class openerp_dav_handler(dav_interface):
""" delete a collection """
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
+ if cr: cr.close()
raise DAV_Error, 409
+
node = self.uri2object(cr, uid, pool, uri2)
- node.rmcol(cr)
+ self._try_function(node.rmcol, (cr,), "rmcol %s" % uri, cr=cr)
cr.commit()
cr.close()
@@ -505,11 +564,12 @@ class openerp_dav_handler(dav_interface):
def rm(self,uri):
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
if not dbname:
- cr.close()
+ if cr: cr.close()
raise DAV_Error, 409
node = self.uri2object(cr, uid, pool, uri2)
- res = node.rm(cr)
+ res = self._try_function(node.rm, (cr,), "rm %s" % uri, cr=cr)
if not res:
+ if cr: cr.close()
raise OSError(1, 'Operation not permited.')
cr.commit()
cr.close()
@@ -671,7 +731,7 @@ class openerp_dav_handler(dav_interface):
node = self.uri2object(cr, uid, pool, uri2)
if node:
result = True
- except:
+ except Exception:
pass
cr.close()
return result
diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py
index f2f57c77730..1502ff204f8 100644
--- a/addons/document_webdav/webdav.py
+++ b/addons/document_webdav/webdav.py
@@ -30,21 +30,24 @@ import tools
super_mk_prop_response = PROPFIND.mk_prop_response
-def mk_prop_response(self, uri, good_props, bad_props, doc):
- """ make a new result element
+def mk_prop_response(self, uri, good_props, bad_props, doc):
+ """ make a new result element
We differ between the good props and the bad ones for
each generating an extra -Node (for each error
one, that means).
-
- """
+
+ """
re=doc.createElement("D:response")
# append namespaces to response
nsnum=0
- for nsname in self.namespaces:
+ namespaces = self.namespaces
+ if 'DAV:' in namespaces:
+ namespaces.remove('DAV:')
+ for nsname in namespaces:
re.setAttribute("xmlns:ns"+str(nsnum),nsname)
nsnum=nsnum+1
-
+
# write href information
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
@@ -64,24 +67,30 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
gp=doc.createElement("D:prop")
for ns in good_props.keys():
- ns_prefix="ns"+str(self.namespaces.index(ns))+":"
- for p,v in good_props[ns].items():
+ if ns == 'DAV:':
+ ns_prefix = 'D:'
+ else:
+ ns_prefix="ns"+str(namespaces.index(ns))+":"
+ for p,v in good_props[ns].items():
if not v:
- pass
+ continue
pe=doc.createElement(ns_prefix+str(p))
if hasattr(v, '__class__') and v.__class__.__name__ == 'Element':
pe.appendChild(v)
else:
- if p=="resourcetype":
- if v==1:
+ if ns == 'DAV:' and p=="resourcetype":
+ if v == 1:
ve=doc.createElement("D:collection")
pe.appendChild(ve)
+ elif isinstance(v,tuple) and v[1] == ns:
+ ve=doc.createElement(ns_prefix+v[0])
+ pe.appendChild(ve)
else:
ve=doc.createTextNode(tools.ustr(v))
pe.appendChild(ve)
gp.appendChild(pe)
-
+
ps.appendChild(gp)
s=doc.createElement("D:status")
t=doc.createTextNode("HTTP/1.1 200 OK")
@@ -100,12 +109,15 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
ps.appendChild(bp)
for ns in bad_props[ecode].keys():
- ns_prefix="ns"+str(self.namespaces.index(ns))+":"
-
+ if ns == 'DAV:':
+ ns_prefix='D:'
+ else:
+ ns_prefix="ns"+str(self.namespaces.index(ns))+":"
+
for p in bad_props[ecode][ns]:
pe=doc.createElement(ns_prefix+str(p))
bp.appendChild(pe)
-
+
s=doc.createElement("D:status")
t=doc.createTextNode(utils.gen_estring(ecode))
s.appendChild(t)
@@ -114,10 +126,10 @@ def mk_prop_response(self, uri, good_props, bad_props, doc):
# return the new response element
return re
-
+
def mk_propname_response(self,uri,propnames,doc):
- """ make a new result element for a PROPNAME request
+ """ make a new result element for a PROPNAME request
This will simply format the propnames list.
propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
@@ -143,16 +155,20 @@ def mk_propname_response(self,uri,propnames,doc):
for ns,plist in propnames.items():
# write prop element
pr=doc.createElement("D:prop")
- nsp="ns"+str(nsnum)
- pr.setAttribute("xmlns:"+nsp,ns)
- nsnum=nsnum+1
+ if ns == 'DAV':
+ nsp = 'D'
+ else:
+ nsp="ns"+str(nsnum)
+ ps.setAttribute("xmlns:"+nsp,ns)
+ nsnum=nsnum+1
- # write propertynames
- for p in plist:
- pe=doc.createElement(nsp+":"+p)
- pr.appendChild(pe)
+ # write propertynames
+ for p in plist:
+ pe=doc.createElement(nsp+":"+p)
+ pr.appendChild(pe)
+
+ ps.appendChild(pr)
- ps.appendChild(pr)
re.appendChild(ps)
return re
diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py
index 9f9f2733a68..0f306a70612 100644
--- a/addons/document_webdav/webdav_server.py
+++ b/addons/document_webdav/webdav_server.py
@@ -32,12 +32,13 @@ import tools
from dav_fs import openerp_dav_handler
from tools.config import config
from DAV.WebDAVServer import DAVRequestHandler
-from service.websrv_lib import HTTPDir,FixSendError
+from service.websrv_lib import HTTPDir, FixSendError, HttpOptions
from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import urllib
from string import atoi,split
from DAV.errors import *
+# from DAV.constants import DAV_VERSION_1, DAV_VERSION_2
def OpenDAVConfig(**kw):
class OpenDAV:
@@ -53,10 +54,15 @@ def OpenDAVConfig(**kw):
return Config()
-class DAVHandler(FixSendError,DAVRequestHandler):
+class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler):
verbose = False
protocol_version = 'HTTP/1.1'
-
+ _HTTP_OPTIONS= { 'DAV' : ['1',],
+ 'Allow' : [ 'GET', 'HEAD', 'COPY', 'MOVE', 'POST', 'PUT',
+ 'PROPFIND', 'PROPPATCH', 'OPTIONS', 'MKCOL',
+ 'DELETE', 'TRACE', 'REPORT', ]
+ }
+
def get_userinfo(self,user,pw):
return False
def _log(self, message):
@@ -99,6 +105,21 @@ class DAVHandler(FixSendError,DAVRequestHandler):
def log_error(self, format, *args):
netsvc.Logger().notifyChannel('xmlrpc', netsvc.LOG_WARNING, format % args)
+ def _prep_OPTIONS(self, opts):
+ ret = opts
+ dc=self.IFACE_CLASS
+ uri=urlparse.urljoin(self.get_baseuri(dc), self.path)
+ uri=urllib.unquote(uri)
+ try:
+ #location = dc.put(uri,body,ct)
+ ret = dc.prep_http_options(uri, opts)
+ except DAV_Error, (ec,dd):
+ pass
+ except Exception,e:
+ self.log_error("Error at options: %s", str(e))
+ raise
+ return ret
+
def send_response(self, code, message=None):
# the BufferingHttpServer will send Connection: close , while
# the BaseHTTPRequestHandler will only accept int code.
diff --git a/addons/project_caldav/project_caldav_data.xml b/addons/project_caldav/project_caldav_data.xml
index e5e2ce0578d..0a4d36580fc 100644
--- a/addons/project_caldav/project_caldav_data.xml
+++ b/addons/project_caldav/project_caldav_data.xml
@@ -51,12 +51,17 @@
field
+