CalDAV: more properties, hide WebCal support

WebCal entries, although permitted by the protocol, confuse some badly
implemented CalDAV clients, so hide them with an option at the calendar
definition.

bzr revid: p_christ@hol.gr-20101012104044-rjx63ucwjk0ys98r
This commit is contained in:
P. Christeas 2010-10-12 13:40:44 +03:00
parent f7ce71c475
commit 95de197440
4 changed files with 101 additions and 43 deletions

View File

@ -24,6 +24,7 @@ from document_webdav import nodes
from document.nodes import _str2time
import logging
import StringIO
from orm_utils import get_last_modified
from tools.dict_tools import dict_merge, dict_merge2
@ -64,21 +65,24 @@ class node_calendar_collection(nodes.node_dir):
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 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
@ -116,7 +120,7 @@ class node_calendar_res_col(nodes.node_res_obj):
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 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
@ -125,8 +129,15 @@ class node_calendar_res_col(nodes.node_res_obj):
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'
@ -138,7 +149,9 @@ class node_calendar(nodes.node_class):
"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',
@ -154,7 +167,9 @@ class node_calendar(nodes.node_class):
# "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'] }
@ -167,8 +182,12 @@ class node_calendar(nodes.node_class):
self.content_length = 0
self.displayname = calendar.name
self.cal_type = calendar.type
# TODO owner
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):
dirobj = self.context._dirobj
@ -186,8 +205,9 @@ class node_calendar(nodes.node_class):
def get_dav_resourcetype(self, cr):
res = [ ('collection', 'DAV:'),
('calendar', 'urn:ietf:params:xml:ns:caldav'),
(str(self.cal_type + '-collection'), 'http://groupdav.org/'),
('calendar', 'urn:ietf:params:xml:ns:caldav') ]
]
return res
def get_domain(self, cr, filters):
@ -373,6 +393,12 @@ class node_calendar(nodes.node_class):
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'
@ -445,7 +471,6 @@ class res_node_calendar(nodes.node_class):
res = '%d' % (self.calendar_id)
return res
def rm(self, cr):
uid = self.context.uid
res = False

View File

@ -74,6 +74,9 @@
<field name="type"/>
<field name="user_id"/>
<field name="collection_id" required="1"/>
<field name="has_webcal" groups="base.group_extended" />
<field name="calendar_color" groups="base.group_extended" />
<field name="calendar_order" groups="base.group_extended" />
<notebook colspan="4">
<page string="Calendar Lines">
<field name="line_ids" mode="form,tree" colspan="4" nolabel="1">

View File

@ -32,6 +32,7 @@ import tools
import time
import logging
from caldav_node import res_node_calendar
from orm_utils import get_last_modified
from tools.safe_eval import safe_eval as eval
try:
@ -552,33 +553,6 @@ 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'
@ -607,6 +581,13 @@ class Calendar(CalDAV, osv.osv):
'create_date': fields.datetime('Created Date', readonly=True),
'write_date': fields.datetime('Modifided Date', readonly=True),
'description': fields.text("description"),
'calendar_color': fields.char('Color', size=20, help="For supporting clients, the color of the calendar entries"),
'calendar_order': fields.integer('Order', help="For supporting clients, the order of this folder among the calendars"),
'has_webcal': fields.boolean('WebCal', required=True, help="Also export a <name>.ics entry next to the calendar folder, with WebCal content."),
}
_defaults = {
'has_webcal': False,
}
def get_calendar_objects(self, cr, uid, ids, parent=None, domain=None, context=None):

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010 OpenERP SA (www.openerp.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
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]
#eof