CalDAV: properly implement the CTag feature

Instead of using the ETag (which looks at the modification time of
the base.calendar object), aggregate over the contained calendar entries
to find their maximum modification.

bzr revid: p_christ@hol.gr-20101012104037-847evso9mryqom5f
This commit is contained in:
P. Christeas
2010-10-12 13:40:37 +03:00
parent 1b30170525
commit 369cae941e
2 changed files with 69 additions and 29 deletions
+16 -29
View File
@@ -21,33 +21,14 @@
import time
from document_webdav import nodes
from document.nodes import _str2time
import logging
import StringIO
from tools.dict_tools import dict_merge, dict_merge2
# TODO: implement DAV-aware errors, inherit from IOError
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
# Assuming that we have set global properties right, we mark *all*
# directories as having calendar-access.
nodes.node_dir.http_options = dict_merge2(nodes.node_dir.http_options,
@@ -186,10 +167,18 @@ class node_calendar(nodes.node_class):
self.content_length = 0
self.displayname = calendar.name
self.cal_type = calendar.type
# TODO owner
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
@@ -295,11 +284,9 @@ class node_calendar(nodes.node_class):
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)
bc_obj = dirobj.pool.get('basic.calendar')
# 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):
+53
View File
@@ -552,6 +552,33 @@ class CalDAV(object):
self.ical_reset('value')
return res
if True: # we need this indentation level ;)
def get_last_modified(self, cr, user, args, context=None, access_rights_uid=None):
"""Return the last modification date of objects in 'domain'
This function has similar semantics to orm.search(), apart from the
limit, offset and order arguments, which make no sense here.
It is useful when we want to find if the table (aka set of records)
has any modifications we should update at the client.
"""
if context is None:
context = {}
self.pool.get('ir.model.access').check(cr, access_rights_uid or user, self._name, 'read', context=context)
query = self._where_calc(cr, user, args, context=context)
self._apply_ir_rules(cr, user, query, 'read', context=context)
from_clause, where_clause, where_clause_params = query.get_sql()
where_str = where_clause and (" WHERE %s" % where_clause) or ''
cr.execute('SELECT MAX(COALESCE("%s".write_date, "%s".create_date)) FROM ' % (self._table, self._table) +
from_clause + where_str ,
where_clause_params,
debug=self._debug)
res = cr.fetchall()
return res[0][0]
class Calendar(CalDAV, osv.osv):
_name = 'basic.calendar'
_calname = 'calendar'
@@ -610,6 +637,32 @@ class Calendar(CalDAV, osv.osv):
node = res_node_calendar('%s.ics' %data.id, parent, ctx, data, line.object_id.model, data.id)
res.append(node)
return res
def get_cal_max_modified(self, cr, uid, ids, parent=None, domain=None, context=None):
if not context:
context = {}
if not domain:
domain = []
res = None
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
line_domain = eval(line.domain or '[]', context)
line_domain += domain
if ctx_res_id:
line_domain += [('id','=',ctx_res_id)]
mod_obj = self.pool.get(line.object_id.model)
max_data = get_last_modified(mod_obj, cr, uid, line_domain, context=context)
if res and res > max_data:
continue
res = max_data
return res
def export_cal(self, cr, uid, ids, vobj='vevent', context=None):
""" Export Calendar