#
##############################################################################
-import time
from document_webdav import nodes
+from document.nodes import _str2time, nodefd_static
import logging
-import StringIO
+from orm_utils import get_last_modified
-# TODO: implement DAV-aware errors, inherit from IOError
+try:
+ from tools.dict_tools import dict_merge2
+except ImportError:
+ from document.dict_tools import dict_merge2
-def dict_merge(*dicts):
- """ Return a dict with all values of dicts
- """
- res = {}
- for d in dicts:
- res.update(d)
- return res
-
-def dict_merge2(*dicts):
- """ Return a dict with all values of dicts.
- If some key appears twice and contains iterable objects, the values
- are merged (instead of overwritten).
- """
- res = {}
- for d in dicts:
- for k in d.keys():
- if k in res and isinstance(res[k], (list, tuple)):
- res[k] = res[k] + d[k]
- else:
- res[k] = d[k]
- return res
+# TODO: implement DAV-aware errors, inherit from IOError
# Assuming that we have set global properties right, we mark *all*
# directories as having calendar-access.
for cal in fil_obj.browse(cr, uid, ids, context=ctx):
if (not name) or not ext:
res.append(node_calendar(cal.name, self, self.context, cal))
- if (not name) or ext:
+ if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+ # these ones must not see the webcal entry.
+ continue
+ if cal.has_webcal and (not name) or ext:
res.append(res_node_calendar(cal.name+'.ics', self, self.context, cal))
# May be both of them!
return res
- def _get_dav_owner(self, cr):
- # Todo?
- return False
-
def _get_ttag(self, cr):
return 'calen-dir-%d' % self.dir_id
def _get_dav_getctag(self, cr):
- result = self.get_etag(cr)
- return str(result)
+ dirobj = self.context._dirobj
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ where = [('collection_id','=',self.dir_id)]
+ bc_obj = dirobj.pool.get('basic.calendar')
+
+ res = get_last_modified(bc_obj, cr, uid, where, context=ctx)
+ return _str2time(res)
class node_calendar_res_col(nodes.node_res_obj):
""" Calendar collection, as a dynamically created node
for cal in fil_obj.browse(cr, uid, ids, context=ctx):
if (not name) or not ext:
res.append(node_calendar(cal.name, self, self.context, cal))
- if (not name) or ext:
+ if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+ # these ones must not see the webcal entry.
+ continue
+ if cal.has_webcal and (not name) or ext:
res.append(res_node_calendar(cal.name+'.ics', self, self.context, cal))
# May be both of them!
return res
return 'calen-dir-%d' % self.dir_id
def _get_dav_getctag(self, cr):
- result = self.get_etag(cr)
- return str(result)
+ dirobj = self.context._dirobj
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ where = [('collection_id','=',self.dir_id)]
+ bc_obj = dirobj.pool.get('basic.calendar')
+
+ res = get_last_modified(bc_obj, cr, uid, where, context=ctx)
+ return _str2time(res)
class node_calendar(nodes.node_class):
our_type = 'collection'
"urn:ietf:params:xml:ns:caldav" : (
'calendar-description',
'supported-calendar-component-set',
- )}
+ ),
+ "http://apple.com/ns/ical/": ("calendar-color", "calendar-order"),
+ }
DAV_PROPS_HIDDEN = {
"urn:ietf:params:xml:ns:caldav" : (
'calendar-data',
# "http://cal.me.com/_namespace/": '_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://apple.com/ns/ical/": '_get_apple_cal',
+ }
http_options = { 'DAV': ['calendar-access'] }
self.content_length = 0
self.displayname = calendar.name
self.cal_type = calendar.type
+ self.cal_color = calendar.calendar_color or None
+ self.cal_order = calendar.calendar_order or None
+ try:
+ self.uuser = (calendar.user_id and calendar.user_id.login) or 'nobody'
+ except Exception:
+ self.uuser = 'nobody'
def _get_dav_getctag(self, cr):
- result = self._get_ttag(cr) + ':' + str(time.time())
- return str(result)
+ dirobj = self.context._dirobj
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+
+ bc_obj = dirobj.pool.get('basic.calendar')
+ res = bc_obj.get_cal_max_modified(cr, uid, [self.calendar_id], self, domain=[], context=ctx)
+ return _str2time(res)
def _get_dav_user_state(self, cr):
#TODO
def get_dav_resourcetype(self, cr):
res = [ ('collection', 'DAV:'),
- (str(self.cal_type + '-collection'), 'http://groupdav.org/'),
- ('calendar', 'urn:ietf:params:xml:ns:caldav') ]
+ ('calendar', 'urn:ietf:params:xml:ns:caldav'),
+ ]
+ if self.context.get('DAV-client', '') == 'GroupDAV':
+ res.append((str(self.cal_type + '-collection'), 'http://groupdav.org/'))
return res
def get_domain(self, cr, filters):
_log.debug("Unknown calendar-query element: %s", filter_child.localName)
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)
- else:
- _log.debug("Unknonwn multiget element: %s", filter_child.localName)
- res = [('name','in',names)]
- return res
+ # this is not the place to process, as it wouldn't support multi-level
+ # hrefs. So, the code is moved to document_webdav/dav_fs.py
+ pass
else:
_log.debug("Unknown element in REPORT: %s", filters.localName)
return res
ctx = self.context.context.copy()
ctx.update(self.dctx)
where = []
+ bc_obj = dirobj.pool.get('basic.calendar')
+
if name:
if name.endswith('.ics'):
name = name[:-4]
try:
- where.append(('id','=',int(name)))
+ if name.isdigit():
+ where.append(('id','=',int(name)))
+ else:
+ bca_obj = dirobj.pool.get('basic.calendar.alias')
+ bc_alias = bca_obj.search(cr, uid,
+ [('cal_line_id.calendar_id', '=', self.calendar_id),
+ ('name', '=', name)] )
+ if not bc_alias:
+ return []
+ bc_val = bca_obj.read(cr, uid, bc_alias, ['res_id',])
+ where.append(('id', '=', bc_val[0]['res_id']))
except ValueError:
# if somebody requests any other name than the ones we
# generate (non-numeric), it just won't exist
- # FIXME: however, this confuses Evolution (at least), which
- # thinks the .ics node hadn't been saved.
return []
if not domain:
domain = []
- 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)
+ # we /could/ be supplying an invalid calendar id to bc_obj, it has to check
+ res = bc_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx)
return res
def create_child(self, cr, path, data):
assert isinstance(res[0], (int, long))
fnodes = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self,
domain=[('id','=',res[0])], context=ctx)
+ if self.context.get('DAV-client','') in ('iPhone', 'iCalendar',):
+ # For those buggy clients, register the alias
+ bca_obj = fil_obj.pool.get('basic.calendar.alias')
+ ourcal = fil_obj.browse(cr, uid, self.calendar_id)
+ line_id = None
+ for line in ourcal.line_ids:
+ if line.name == ourcal.type:
+ line_id = line.id
+ break
+ assert line_id, "Calendar #%d must have at least one %s line" % \
+ (ourcal.id, ourcal.type)
+ if path.endswith('.ics'):
+ path = path[:-4]
+ bca_obj.create(cr, uid, { 'cal_line_id': line_id,
+ 'res_id': res[0], 'name': path}, context=ctx)
return fnodes[0]
# If we reach this line, it means that we couldn't import any useful
# (and matching type vs. our node kind) data from the iCal content.
return False
def _get_caldav_calendar_data(self, cr):
+ if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+ # Never return collective data to iClients, they get confused
+ # because they do propfind on the calendar node with Depth=1
+ # and only expect the childrens' data
+ return None
res = []
for child in self.children(cr):
res.append(child._get_caldav_calendar_data(cr))
return res
+ def open_data(self, cr, mode):
+ return nodefd_static(self, cr, mode)
+
def _get_caldav_calendar_description(self, cr):
uid = self.context.uid
calendar_obj = self.context._dirobj.pool.get('basic.calendar')
try:
calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
return calendar.description or calendar.name
- except Exception, e:
+ except Exception:
return None
def _get_dav_supported_report_set(self, cr):
def _get_caldav_max_date_time(self, cr):
return "21001231T235959Z" # I will be dead by then
+
+ def _get_apple_cal_calendar_color(self, cr):
+ return self.cal_color
+
+ def _get_apple_cal_calendar_order(self, cr):
+ return self.cal_order
class res_node_calendar(nodes.node_class):
our_type = 'file'
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
- pr = res_obj.perm_read()[0]
+ pr = res_obj.perm_read(context=context, details=False)[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.model = res_model
self.res_id = res_id
- def open(self, cr, mode=False):
- if self.type in ('collection','database'):
- return False
- s = StringIO.StringIO(self.get_data(cr))
- s.name = self
- return s
+ def open_data(self, cr, mode):
+ return nodefd_static(self, cr, mode)
- 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()
res = '%d' % (self.calendar_id)
return res
-
def rm(self, cr):
uid = self.context.uid
res = False