changeset 4843:e4b72700f1c0

health_caldav: Refactor package. GH naming and migration to 4.0
author Luis Falcon <falcon@gnuhealth.org>
date Tue, 11 Jan 2022 18:43:16 +0000
parents 66515b54d4a3
children 0e76aeab5dc4
files tryton/health_caldav/__init__.py tryton/health_caldav/caldav.py tryton/health_caldav/calendar.xml tryton/health_caldav/calendar_.py tryton/health_caldav/exceptions.py tryton/health_caldav/security/access_rights.xml tryton/health_caldav/setup.py tryton/health_caldav/tests/scenario_calendar.py.bak tryton/health_caldav/tryton.cfg
diffstat 9 files changed, 370 insertions(+), 545 deletions(-) [+]
line wrap: on
line diff
--- a/tryton/health_caldav/__init__.py
+++ b/tryton/health_caldav/__init__.py
@@ -13,26 +13,26 @@
 
 from trytond.pool import Pool
 from . import caldav
-from .webdav import *
-from .calendar_ import *
-from .res import *
+from . import webdav
+from . import calendar_
+from . import res
 
 
 def register():
     Pool.register(
-        Collection,
-        Calendar,
-        ReadUser,
-        WriteUser,
-        Category,
-        Location,
-        Event,
-        EventCategory,
-        EventAlarm,
-        EventAttendee,
-        EventRDate,
-        EventExDate,
-        EventRRule,
-        EventExRule,
-        User,
-        module='calendar', type_='model')
+        webdav.Collection,
+        calendar_.Calendar,
+        calendar_.ReadUser,
+        calendar_.WriteUser,
+        calendar_.Category,
+        calendar_.Location,
+        calendar_.Event,
+        calendar_.EventCategory,
+        calendar_.EventAlarm,
+        calendar_.EventAttendee,
+        calendar_.EventRDate,
+        calendar_.EventExDate,
+        calendar_.EventRRule,
+        calendar_.EventExRule,
+        res.User,
+        module='health_caldav', type_='model')
--- a/tryton/health_caldav/caldav.py
+++ b/tryton/health_caldav/caldav.py
@@ -8,7 +8,7 @@
 from pywebdav.lib.errors import DAV_NotFound, DAV_Error, DAV_Forbidden
 from pywebdav.lib.utils import get_uriparentpath
 from pywebdav.lib.constants import DAV_VERSION_1, DAV_VERSION_2
-from trytond.modules.webdav.protocol import TrytonDAVInterface, LOCAL, \
+from trytond.modules.health_webdav3_server.protocol import TrytonDAVInterface, LOCAL, \
         WebDAVAuthRequestHandler
 from trytond.pool import Pool
 from trytond.transaction import Transaction
--- a/tryton/health_caldav/calendar.xml
+++ b/tryton/health_caldav/calendar.xml
@@ -4,20 +4,6 @@
 <tryton>
     <data>
 
-        <record model="res.group" id="group_calendar_admin">
-            <field name="name">Calendar Administration</field>
-        </record>
-        <record model="res.user-res.group"
-            id="user_admin_group_calendar_admin">
-            <field name="user" ref="res.user_admin"/>
-            <field name="group" ref="group_calendar_admin"/>
-        </record>
-        <record model="res.user-res.group"
-            id="user_trigger_group_calendar_admin">
-            <field name="user" ref="res.user_trigger"/>
-            <field name="group" ref="group_calendar_admin"/>
-        </record>
-
         <menuitem name="Calendar" sequence="8" id="menu_calendar"
             icon="tryton-calendar"/>
 
@@ -47,70 +33,6 @@
         </record>
         <menuitem parent="menu_calendar" sequence="1"
             action="act_calendar_form" id="menu_calendar_form"/>
-
-        <record model="ir.rule.group" id="rule_group_calendar_admin">
-            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="False"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule" id="rule_group_calendar_admin_line1">
-            <field name="domain">[]</field>
-            <field name="rule_group" ref="rule_group_calendar_admin"/>
-        </record>
-        <record model="ir.rule.group-res.group"
-            id="rule_group_calendar_admin-calendar_admin">
-            <field name="rule_group" ref="rule_group_calendar_admin"/>
-            <field name="group" ref="group_calendar_admin"/>
-        </record>
-
-        <record model="ir.rule.group" id="rule_group_read_calendar">
-            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="True"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="False"/>
-            <field name="perm_create" eval="False"/>
-            <field name="perm_delete" eval="False"/>
-        </record>
-        <record model="ir.rule" id="rule_group_read_calendar_line1">
-            <field name="domain"
-                eval="[('owner', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_read_calendar"/>
-        </record>
-        <record model="ir.rule" id="rule_group_read_calendar_line2">
-            <field name="domain"
-                eval="[('read_users', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_read_calendar"/>
-        </record>
-
-        <record model="ir.rule.group" id="rule_group_write_calendar">
-            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="True"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule" id="rule_group_write_calendar_line1">
-            <field name="domain"
-                eval="[('owner', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_write_calendar"/>
-        </record>
-        <record model="ir.rule" id="rule_group_write_calendar_line2">
-            <field name="domain"
-                eval="[('write_users', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_write_calendar"/>
-        </record>
-
         <record model="ir.ui.view" id="category_view_tree">
             <field name="model">calendar.category</field>
             <field name="type">tree</field>
@@ -173,69 +95,6 @@
         <menuitem parent="menu_calendar_form" sequence="20"
             action="act_event_form" id="menu_event_form"/>
 
-        <record model="ir.rule.group" id="rule_group_event_admin">
-            <field name="model" search="[('model', '=', 'calendar.event')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="False"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule" id="rule_group_event_admin_line1">
-            <field name="domain" eval="[]" pyson="1"/>
-            <field name="rule_group" ref="rule_group_event_admin"/>
-        </record>
-        <record model="ir.rule.group-res.group"
-            id="rule_group_event_admin-calendar_admin">
-            <field name="rule_group" ref="rule_group_event_admin"/>
-            <field name="group" ref="group_calendar_admin"/>
-        </record>
-
-        <record model="ir.rule.group" id="rule_group_read_event">
-            <field name="model" search="[('model', '=', 'calendar.event')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="True"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="False"/>
-            <field name="perm_create" eval="False"/>
-            <field name="perm_delete" eval="False"/>
-        </record>
-        <record model="ir.rule" id="rule_group_read_event_line1">
-            <field name="domain"
-                eval="[('calendar.owner', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_read_event"/>
-        </record>
-        <record model="ir.rule" id="rule_group_read_event_line2">
-            <field name="domain"
-                eval="[('calendar.read_users', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_read_event"/>
-        </record>
-
-        <record model="ir.rule.group" id="rule_group_write_event">
-            <field name="model" search="[('model', '=', 'calendar.event')]"/>
-            <field name="global_p" eval="False"/>
-            <field name="default_p" eval="True"/>
-            <field name="perm_read" eval="True"/>
-            <field name="perm_write" eval="True"/>
-            <field name="perm_create" eval="True"/>
-            <field name="perm_delete" eval="True"/>
-        </record>
-        <record model="ir.rule" id="rule_group_write_event_line1">
-            <field name="domain"
-                eval="[('calendar.owner', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_write_event"/>
-        </record>
-        <record model="ir.rule" id="rule_group_write_event_line2">
-            <field name="domain"
-                eval="[('calendar.write_users', '=', Eval('user', {}).get('id', -1))]"
-                pyson="1"/>
-            <field name="rule_group" ref="rule_group_write_event"/>
-        </record>
-
         <record model="ir.action.act_window" id="act_event_form3">
             <field name="name">Events</field>
             <field name="res_model">calendar.event</field>
--- a/tryton/health_caldav/calendar_.py
+++ b/tryton/health_caldav/calendar_.py
@@ -6,12 +6,11 @@
 import pytz
 import datetime
 import xml.dom.minidom
-from sql import Table, Column, Null
+from sql import Null
 
 from trytond.model import Model, ModelSQL, ModelView, fields, Check, Unique
 from trytond.tools import reduce_ids, grouped_slice
-from trytond import backend
-from trytond.pyson import If, Bool, Eval, PYSONEncoder
+from trytond.pyson import If, Bool, Eval
 from trytond.transaction import Transaction
 from trytond.cache import Cache
 from trytond.pool import Pool
@@ -23,12 +22,15 @@
     InvalidByHour, InvalidByDay,
     InvalidByMonthDay, InvalidByWeekNumber,
     InvalidByYearDay,
-    InvalidByMonth, InvalidByPosition)
+    InvalidByMonth, InvalidBySetPosition)
 
 __all__ = ['Calendar', 'ReadUser', 'WriteUser', 'Category', 'Location',
-    'Event', 'EventCategory', 'AlarmMixin', 'EventAlarm', 'AttendeeMixin',
-    'EventAttendee', 'DateMixin', 'EventRDate', 'EventExDate', 'RRuleMixin',
-    'EventRRule', 'EventExRule']
+           'Event', 'EventCategory', 'AlarmMixin', 'EventAlarm',
+           'AttendeeMixin',
+           'EventAttendee', 'DateMixin', 'EventRDate', 'EventExDate',
+           'RRuleMixin',
+           'EventRRule', 'EventExRule']
+
 
 tzlocal = dateutil.tz.tzlocal()
 tzutc = dateutil.tz.tzutc()
@@ -40,13 +42,16 @@
     __name__ = 'calendar.calendar'
     name = fields.Char('Name', required=True, select=True)
     description = fields.Text('Description')
-    owner = fields.Many2One('res.user', 'Owner', select=True,
-            domain=[('email', '!=', None)],
-            help='The user must have an email')
-    read_users = fields.Many2Many('calendar.calendar-read-res.user',
-            'calendar', 'user', 'Read Users')
-    write_users = fields.Many2Many('calendar.calendar-write-res.user',
-            'calendar', 'user', 'Write Users')
+    owner = fields.Many2One(
+        'res.user', 'Owner', select=True,
+        domain=[('email', '!=', None)],
+        help='The user must have an email')
+    read_users = fields.Many2Many(
+        'calendar.calendar-read-res.user',
+        'calendar', 'user', 'Read Users')
+    write_users = fields.Many2Many(
+        'calendar.calendar-write-res.user',
+        'calendar', 'user', 'Write Users')
     _get_name_cache = Cache('calendar_calendar.get_name')
 
     @classmethod
@@ -94,7 +99,6 @@
             raise InvalidCalendarExtension(
                 gettext('health_caldav.msg_invalid_calendar_extension'))
 
-
     @classmethod
     def get_name(cls, name):
         '''
@@ -201,7 +205,7 @@
                         ('exdates', '!=', None),
                         ('exrules', '!=', None),
                         ('occurences', '!=', None),
-                        ],
+                     ],
                     ('calendar', '=', calendar_id),
                     ])
 
@@ -220,7 +224,7 @@
                     f_dtstart_tz = freebusy_dtstart.replace(tzinfo=tzlocal)
                     f_dtend_tz = freebusy_dtend.replace(tzinfo=tzlocal)
                     if not ((f_dtstart_tz <= dtstart
-                                and f_dtend_tz >= dtstart)
+                             and f_dtend_tz >= dtstart)
                             or (f_dtstart_tz <= dtend
                                 and f_dtend_tz >= dtend)
                             or (f_dtstart_tz >= dtstart
@@ -325,8 +329,9 @@
                     vfreebusy.vfreebusy.add('attendee').value = attendee.value
 
                 status = doc.createElement('C:request-status')
-                status.appendChild(doc.createTextNode(vfreebusy
-                        and '2.0;Success'
+                status.appendChild(
+                    doc.createTextNode(
+                        vfreebusy and '2.0;Success'
                         or '5.3;No scheduling support for user.'))
                 resp.appendChild(status)
                 if vfreebusy:
@@ -340,19 +345,24 @@
 class ReadUser(ModelSQL):
     'Calendar - read - User'
     __name__ = 'calendar.calendar-read-res.user'
-    calendar = fields.Many2One('calendar.calendar', 'Calendar',
-            ondelete='CASCADE', required=True, select=True)
-    user = fields.Many2One('res.user', 'User', ondelete='CASCADE',
-            required=True, select=True)
+    calendar = fields.Many2One(
+        'calendar.calendar', 'Calendar',
+        ondelete='CASCADE', required=True, select=True)
+    user = fields.Many2One(
+        'res.user', 'User', ondelete='CASCADE',
+        required=True, select=True)
 
 
 class WriteUser(ModelSQL):
     'Calendar - write - User'
     __name__ = 'calendar.calendar-write-res.user'
-    calendar = fields.Many2One('calendar.calendar', 'Calendar',
-            ondelete='CASCADE', required=True, select=True)
-    user = fields.Many2One('res.user', 'User', ondelete='CASCADE',
-            required=True, select=True)
+    calendar = fields.Many2One(
+        'calendar.calendar', 'Calendar',
+        ondelete='CASCADE', required=True, select=True)
+
+    user = fields.Many2One(
+        'res.user', 'User', ondelete='CASCADE',
+        required=True, select=True)
 
 
 class Category(ModelSQL, ModelView):
@@ -391,10 +401,12 @@
     "Event"
     __name__ = 'calendar.event'
     _rec_name = 'uuid'
-    uuid = fields.Char('UUID', required=True,
-            help='Universally Unique Identifier', select=True)
-    calendar = fields.Many2One('calendar.calendar', 'Calendar',
-            required=True, select=True, ondelete="CASCADE")
+    uuid = fields.Char(
+        'UUID', required=True,
+        help='Universally Unique Identifier', select=True)
+    calendar = fields.Many2One(
+        'calendar.calendar', 'Calendar',
+        required=True, select=True, ondelete="CASCADE")
     summary = fields.Char('Summary')
     sequence = fields.Integer('Sequence', required=True)
     description = fields.Text('Description')
@@ -402,8 +414,9 @@
     dtstart = fields.DateTime('Start Date', required=True, select=True)
     dtend = fields.DateTime('End Date', select=True)
     timezone = fields.Selection('timezones', 'Timezone')
-    categories = fields.Many2Many('calendar.event-calendar.category',
-            'event', 'category', 'Categories')
+    categories = fields.Many2Many(
+        'calendar.event-calendar.category',
+        'event', 'category', 'Categories')
     classification = fields.Selection([
         ('public', 'Public'),
         ('private', 'Private'),
@@ -419,34 +432,40 @@
     organizer = fields.Char('Organizer', states={
             'required': If(Bool(Eval('attendees')), ~Eval('parent'), False),
             }, depends=['attendees', 'parent'])
-    attendees = fields.One2Many('calendar.event.attendee', 'event',
-            'Attendees')
+    attendees = fields.One2Many(
+        'calendar.event.attendee', 'event',
+        'Attendees')
     transp = fields.Selection([
         ('opaque', 'Opaque'),
         ('transparent', 'Transparent'),
         ], 'Time Transparency', required=True)
     alarms = fields.One2Many('calendar.event.alarm', 'event', 'Alarms')
-    rdates = fields.One2Many('calendar.event.rdate', 'event',
+    rdates = fields.One2Many(
+        'calendar.event.rdate', 'event',
         'Recurrence Dates',
         states={
             'invisible': Bool(Eval('parent')),
             }, depends=['parent'])
-    rrules = fields.One2Many('calendar.event.rrule', 'event',
+    rrules = fields.One2Many(
+        'calendar.event.rrule', 'event',
         'Recurrence Rules',
         states={
             'invisible': Bool(Eval('parent')),
             }, depends=['parent'])
-    exdates = fields.One2Many('calendar.event.exdate', 'event',
+    exdates = fields.One2Many(
+        'calendar.event.exdate', 'event',
         'Exception Dates',
         states={
             'invisible': Bool(Eval('parent')),
             }, depends=['parent'])
-    exrules = fields.One2Many('calendar.event.exrule', 'event',
+    exrules = fields.One2Many(
+        'calendar.event.exrule', 'event',
         'Exception Rules',
         states={
             'invisible': Bool(Eval('parent')),
             }, depends=['parent'])
-    occurences = fields.One2Many('calendar.event', 'parent', 'Occurences',
+    occurences = fields.One2Many(
+        'calendar.event', 'parent', 'Occurences',
         domain=[
             ('uuid', '=', Eval('uuid')),
             ('calendar', '=', Eval('calendar')),
@@ -454,7 +473,8 @@
         states={
             'invisible': Bool(Eval('parent')),
             }, depends=['uuid', 'calendar', 'parent'])
-    parent = fields.Many2One('calendar.event', 'Parent',
+    parent = fields.Many2One(
+        'calendar.event', 'Parent',
         domain=[
             ('uuid', '=', Eval('uuid')),
             ('parent', '=', None),
@@ -550,17 +570,17 @@
         for event in events:
             if (event.calendar.owner
                     and (event.organizer == event.calendar.owner.email
-                        or (event.parent
-                            and event.parent.organizer ==
-                            event.parent.calendar.owner.email))):
+                         or (event.parent
+                             and event.parent.organizer ==
+                             event.parent.calendar.owner.email))):
                 if event.organizer == event.calendar.owner.email:
                     attendee_emails = [x.email for x in event.attendees
-                            if x.status != 'declined'
-                            and x.email != event.organizer]
+                                       if x.status != 'declined'
+                                       and x.email != event.organizer]
                 else:
                     attendee_emails = [x.email for x in event.parent.attendees
-                            if x.status != 'declined'
-                            and x.email != event.parent.organizer]
+                                       if x.status != 'declined'
+                                       and x.email != event.parent.organizer]
                 if attendee_emails:
                     with Transaction().set_user(0):
                         calendars = Calendar.search([
@@ -609,16 +629,16 @@
             'organizer': self.organizer,
             'rdates': [('delete', [r.id for r in self.rdates])]
             + [('create', [rdate._date2update()
-                        for rdate in self.rdates])],
+                           for rdate in self.rdates])],
             'exdates': [('delete', [r.id for r in self.exdates])]
             + [('create', [exdate._date2update()
-                        for exdate in self.exdates])],
+                           for exdate in self.exdates])],
             'rrules': [('delete', [r.id for r in self.rrules])]
             + [('create', [rrule._date2update()
-                        for rrule in self.rrules])],
+                           for rrule in self.rrules])],
             'exrules': [('delete', [r.id for r in self.exrules])]
             + [('create', [exrule._date2update()
-                        for exrule in self.exrules])],
+                           for exrule in self.exrules])],
             }
 
     @classmethod
@@ -654,18 +674,19 @@
             for event in events:
                 if (event.calendar.owner
                         and (event.organizer == event.calendar.owner.email
-                            or (event.parent
-                                and event.parent.organizer
-                                == event.calendar.owner.email))):
+                             or (event.parent
+                                 and event.parent.organizer
+                                 == event.calendar.owner.email))):
                     if event.organizer == event.calendar.owner.email:
                         attendee_emails = [x.email for x in event.attendees
-                                if x.status != 'declined'
-                                and x.email != event.organizer]
+                                           if x.status != 'declined'
+                                           and x.email != event.organizer]
                     else:
                         attendee_emails = [x.email
-                            for x in event.parent.attendees
-                            if x.status != 'declined'
-                            and x.email != event.parent.organizer]
+                                           for x in event.parent.attendees
+                                           if x.status != 'declined'
+                                           and x.email !=
+                                           event.parent.organizer]
                     with Transaction().set_user(0):
                         events2 = cls.search([
                                 ('uuid', '=', event.uuid),
@@ -726,7 +747,7 @@
             current_default = default.copy()
             current_default.setdefault('uuid', cls.default_uuid())
             new_events.extend(super(Event, cls).copy([event],
-                    default=current_default))
+                              default=current_default))
         return new_events
 
     @classmethod
@@ -738,15 +759,15 @@
         for event in events:
             if (event.calendar.owner
                     and (event.organizer == event.calendar.owner.email
-                        or (event.parent
-                            and event.parent.organizer
-                            == event.calendar.owner.email))):
+                         or (event.parent
+                             and event.parent.organizer
+                             == event.calendar.owner.email))):
                 if event.organizer == event.calendar.owner.email:
                     attendee_emails = [x.email for x in event.attendees
-                            if x.email != event.organizer]
+                                       if x.email != event.organizer]
                 else:
                     attendee_emails = [x.email for x in event.parent.attendees
-                            if x.email != event.parent.organizer]
+                                       if x.email != event.parent.organizer]
                 if attendee_emails:
                     with Transaction().set_user(0):
                         cls.delete(cls.search([
@@ -825,8 +846,9 @@
             res['description'] = None
         if not isinstance(vevent.dtstart.value, datetime.datetime):
             res['all_day'] = True
-            res['dtstart'] = datetime.datetime.combine(vevent.dtstart.value,
-                    datetime.time())
+            res['dtstart'] = datetime.datetime.combine(
+                vevent.dtstart.value,
+                datetime.time())
         else:
             res['all_day'] = False
             if vevent.dtstart.value.tzinfo:
@@ -836,7 +858,7 @@
         if hasattr(vevent, 'dtend'):
             if not isinstance(vevent.dtend.value, datetime.datetime):
                 res['dtend'] = datetime.datetime.combine(vevent.dtend.value,
-                        datetime.time())
+                                                         datetime.time())
             else:
                 if vevent.dtend.value.tzinfo:
                     res['dtend'] = vevent.dtend.value.astimezone(tzlocal)
@@ -932,7 +954,8 @@
                 vals = Attendee.attendee2values(attendee)
                 if vals['email'] in attendees_todel:
                     res['attendees'].append(('write',
-                        [attendees_todel[vals['email']]], vals))
+                                            [attendees_todel[vals['email']]],
+                                            vals))
                     del attendees_todel[vals['email']]
                 else:
                     to_create.append(vals)
@@ -1180,10 +1203,12 @@
 class EventCategory(ModelSQL):
     'Event - Category'
     __name__ = 'calendar.event-calendar.category'
-    event = fields.Many2One('calendar.event', 'Event', ondelete='CASCADE',
-            required=True, select=True)
-    category = fields.Many2One('calendar.category', 'Category',
-            ondelete='CASCADE', required=True, select=True)
+    event = fields.Many2One(
+        'calendar.event', 'Event', ondelete='CASCADE',
+        required=True, select=True)
+    category = fields.Many2One(
+        'calendar.category', 'Category',
+        ondelete='CASCADE', required=True, select=True)
 
 
 class AlarmMixin:
@@ -1209,27 +1234,9 @@
 class EventAlarm(AlarmMixin, ModelSQL, ModelView):
     'Alarm'
     __name__ = 'calendar.event.alarm'
-    event = fields.Many2One('calendar.event', 'Event', ondelete='CASCADE',
-            required=True, select=True)
-
-    @classmethod
-    def __register__(cls, module_name):
-        TableHandler = backend.get('TableHandler')
-        cursor = Transaction().connection.cursor()
-        sql_table = cls.__table__()
-
-        super(EventAlarm, cls).__register__(module_name)
-
-        table = TableHandler(cls, module_name)
-
-        # Migration from 2.6: Remove inherits calendar.alarm
-        if table.column_exist('calendar_alarm'):
-            alarm = Table('calendar_alarm')
-            cursor.execute(*sql_table.update(
-                    columns=[sql_table.valarm],
-                    values=[alarm.select(alarm.valarm,
-                            where=alarm.id == sql_table.calendar_alarm)]))
-            table.drop_column('calendar_alarm', True)
+    event = fields.Many2One(
+        'calendar.event', 'Event', ondelete='CASCADE',
+        required=True, select=True)
 
     @classmethod
     def create(cls, vlist):
@@ -1338,32 +1345,11 @@
 class EventAttendee(AttendeeMixin, ModelSQL, ModelView):
     'Attendee'
     __name__ = 'calendar.event.attendee'
-    event = fields.Many2One('calendar.event', 'Event', ondelete='CASCADE',
+    event = fields.Many2One(
+        'calendar.event', 'Event', ondelete='CASCADE',
         required=True, select=True)
 
     @classmethod
-    def __register__(cls, module_name):
-        TableHandler = backend.get('TableHandler')
-        cursor = Transaction().connection.cursor()
-        sql_table = cls.__table__()
-
-        super(EventAttendee, cls).__register__(module_name)
-
-        table = TableHandler(cls, module_name)
-
-        # Migration from 2.6: Remove inherits calendar.attendee
-        if table.column_exist('calendar_attendee'):
-            attendee = Table('calendar_attendee')
-            cursor.execute(*sql_table.update(
-                    columns=[sql_table.email, sql_table.status],
-                    values=[attendee.select(attendee.email,
-                            where=attendee.id == sql_table.calendar_attendee),
-                        attendee.select(attendee.status,
-                            where=attendee.id == sql_table.calendar_attendee),
-                        ]))
-            table.drop_column('calendar_attendee', True)
-
-    @classmethod
     def create(cls, vlist):
         Event = Pool().get('calendar.event')
         to_write = []
@@ -1379,15 +1365,15 @@
             event = event_attendee.event
             if (event.calendar.owner
                     and (event.organizer == event.calendar.owner.email
-                        or (event.parent
-                            and event.parent.organizer ==
-                            event.parent.calendar.owner.email))):
+                         or (event.parent
+                             and event.parent.organizer ==
+                             event.parent.calendar.owner.email))):
                 if event.organizer == event.calendar.owner.email:
                     attendee_emails = [x.email for x in event.attendees
-                            if x.email != event.organizer]
+                                       if x.email != event.organizer]
                 else:
                     attendee_emails = [x.email for x in event.parent.attendees
-                            if x.email != event.parent.organizer]
+                                       if x.email != event.parent.organizer]
                 if attendee_emails:
                     with Transaction().set_user(0):
                         events = Event.search([
@@ -1429,15 +1415,15 @@
             event = event_attendee.event
             if (event.calendar.owner
                     and (event.organizer == event.calendar.owner.email
-                        or (event.parent
-                            and event.parent.organizer
-                            == event.calendar.owner.email))):
+                         or (event.parent
+                             and event.parent.organizer
+                             == event.calendar.owner.email))):
                 if event.organizer == event.calendar.owner.email:
                     attendee_emails = [x.email for x in event.attendees
-                            if x.email != event.organizer]
+                                       if x.email != event.organizer]
                 else:
                     attendee_emails = [x.email for x in event.parent.attendees
-                            if x.email != event.parent.organizer]
+                                       if x.email != event.parent.organizer]
                 if attendee_emails:
                     with Transaction().set_user(0):
                         other_attendees = cls.search([
@@ -1450,7 +1436,7 @@
                                 ('email', '=', event_attendee.email),
                                 ])
                         cls.write(other_attendees,
-                            event_attendee._attendee2update())
+                                  event_attendee._attendee2update())
 
     @classmethod
     def delete(cls, event_attendees):
@@ -1466,15 +1452,15 @@
             event = attendee.event
             if (event.calendar.owner
                     and (event.organizer == event.calendar.owner.email
-                        or (event.parent
-                            and event.parent.organizer
-                            == event.calendar.owner.email))):
+                         or (event.parent
+                             and event.parent.organizer
+                             == event.calendar.owner.email))):
                 if event.organizer == event.calendar.owner.email:
                     attendee_emails = [x.email for x in event.attendees
-                            if x.email != event.organizer]
+                                       if x.email != event.organizer]
                 else:
                     attendee_emails = [x.email for x in event.parent.attendees
-                            if x.email != event.parent.organizer]
+                                       if x.email != event.parent.organizer]
                 if attendee_emails:
                     with Transaction().set_user(0):
                         attendees = cls.search([
@@ -1489,8 +1475,8 @@
                         cls.delete(attendees)
             elif (event.calendar.owner
                     and ((event.organizer
-                            or (event.parent and event.parent.organizer))
-                        and attendee.email == event.calendar.owner.email)):
+                          or (event.parent and event.parent.organizer))
+                         and attendee.email == event.calendar.owner.email)):
                 if event.organizer:
                     organizer = event.organizer
                 else:
@@ -1512,7 +1498,8 @@
 
 class DateMixin:
     _rec_name = 'datetime'
-    date = fields.Boolean('Is Date',
+    date = fields.Boolean(
+        'Is Date',
         help='Ignore time of field "Date", but handle as date only.')
     datetime = fields.DateTime('Date', required=True)
 
@@ -1531,7 +1518,7 @@
         if not isinstance(date, datetime.datetime):
             res['date'] = True
             res['datetime'] = datetime.datetime.combine(date,
-                    datetime.time())
+                                                        datetime.time())
         else:
             res['date'] = False
             if date.tzinfo:
@@ -1555,34 +1542,9 @@
     'Recurrence Date'
     __name__ = 'calendar.event.rdate'
     _rec_name = 'datetime'
-    event = fields.Many2One('calendar.event', 'Event', ondelete='CASCADE',
-            select=True, required=True)
-
-    @classmethod
-    def __register__(cls, module_name):
-        TableHandler = backend.get('TableHandler')
-        cursor = Transaction().connection.cursor()
-        sql_table = cls.__table__()
-        # Migration from 1.4: calendar_rdate renamed to calendar_date
-        table = TableHandler(cls, module_name)
-        old_column = 'calendar_rdate'
-        if table.column_exist(old_column):
-            table.column_rename(old_column, 'calendar_date')
-
-        super(EventRDate, cls).__register__(module_name)
-
-        table = TableHandler(cls, module_name)
-
-        # Migration from 2.6: Remove inherits calendar.date
-        if table.column_exist('calendar_date'):
-            date = Table('calendar_date')
-            cursor.execute(*sql_table.update(
-                    columns=[sql_table.date, sql_table.datetime],
-                    values=[date.select(date.date,
-                            where=date.id == sql_table.calendar_date),
-                        date.select(date.datetime,
-                            where=date.id == sql_table.calendar_date)]))
-            table.drop_column('calendar_date', True)
+    event = fields.Many2One(
+        'calendar.event', 'Event', ondelete='CASCADE',
+        select=True, required=True)
 
     @classmethod
     def create(cls, vlist):
@@ -1639,7 +1601,8 @@
         ('monthly', 'Monthly'),
         ('yearly', 'Yearly'),
         ], 'Frequency', required=True)
-    until_date = fields.Boolean('Is Date',
+    until_date = fields.Boolean(
+        'Is Date',
         help='Ignore time of field "Until Date", but handle as date only.')
     until = fields.DateTime('Until Date')
     count = fields.Integer('Count')
@@ -1671,7 +1634,7 @@
         cls._sql_constraints += [
             ('until_count_only_one',
                 Check(t,
-                    (t.until == Null) | (t.count == Null) | (t.count == 0)),
+                      (t.until == Null) | (t.count == Null) | (t.count == 0)),
                 'Only one of "until" and "count" can be set.'),
             ]
 
@@ -1700,7 +1663,6 @@
                     raise InvalidBySecond(
                         gettext('health_caldav.msg_invalid_bysecond'))
 
-
     def check_byminute(self):
         if self.byminute:
             for minute in self.byminute.split(','):
@@ -1798,8 +1760,9 @@
 
     def _rule2update(self):
         res = {}
-        for field in ('freq', 'until_date', 'until', 'count', 'interval',
-                'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
+        for field in (
+            'freq', 'until_date', 'until', 'count', 'interval',
+            'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
                 'byyearday', 'byweekno', 'bymonth', 'bysetpos', 'wkst'):
             res[field] = getattr(self, field)
         return res
@@ -1821,7 +1784,7 @@
                 if not isinstance(value, datetime.datetime):
                     res['until_date'] = True
                     res['until'] = datetime.datetime.combine(value,
-                            datetime.time())
+                                                             datetime.time())
                 else:
                     res['until_date'] = False
                     if value.tzinfo:
@@ -1844,7 +1807,8 @@
             if self.until_date:
                 res += vobject.icalendar.dateToString(self.until.date())
             else:
-                res += vobject.icalendar.dateTimeToString(self.until
+                res += vobject.icalendar.dateTimeToString(
+                    self.until
                     .replace(tzinfo=tzlocal).astimezone(tzutc),
                     convertToUTC=True)
         elif self.count:
@@ -1852,8 +1816,9 @@
         for field in ('freq', 'wkst'):
             if getattr(self, field):
                 res += ';' + field.upper() + '=' + getattr(self, field).upper()
-        for field in ('interval', 'bysecond', 'byminute', 'byhour',
-                'byday', 'bymonthday', 'byyearday', 'byweekno',
+        for field in (
+            'interval', 'bysecond', 'byminute', 'byhour',
+            'byday', 'bymonthday', 'byyearday', 'byweekno',
                 'bymonth', 'bysetpos'):
             if getattr(self, field):
                 res += ';' + field.upper() + '=' + str(getattr(self, field))
@@ -1863,29 +1828,9 @@
 class EventRRule(RRuleMixin, ModelSQL, ModelView):
     'Recurrence Rule'
     __name__ = 'calendar.event.rrule'
-    event = fields.Many2One('calendar.event', 'Event', ondelete='CASCADE',
-            select=True, required=True)
-
-    @classmethod
-    def __register__(cls, module_name):
-        TableHandler = backend.get('TableHandler')
-        cursor = Transaction().connection.cursor()
-        sql_table = cls.__table__()
-
-        super(EventRRule, cls).__register__(module_name)
-
-        table = TableHandler(cls, module_name)
-
-        # Migration from 2.6: Remove inherits calendar.rrule
-        if table.column_exist('calendar_rrule'):
-            rrule = Table('calendar_rrule')
-            for field in (f for f in dir(RRuleMixin)
-                    if isinstance(f, fields.Field)):
-                cursor.execute(*sql_table.update(
-                        columns=[Column(sql_table, field)],
-                        values=[rrule.select(Column(rrule, field),
-                                where=rrule.id == sql_table.calendar_rrule)]))
-            table.drop_column('calendar_rrule', True)
+    event = fields.Many2One(
+        'calendar.event', 'Event', ondelete='CASCADE',
+        select=True, required=True)
 
     @classmethod
     def create(cls, vlist):
--- a/tryton/health_caldav/exceptions.py
+++ b/tryton/health_caldav/exceptions.py
@@ -1,9 +1,48 @@
 # This file is part of GNU Health.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
-from trytond.exceptions import UserError, UserWarning
+# from trytond.exceptions import UserError, UserWarning
 from trytond.model.exceptions import ValidationError
 
 
 class InvalidCalendarExtension(ValidationError):
     pass
 
+
+class InvalidRecurrence(ValidationError):
+    pass
+
+
+class InvalidBySecond(ValidationError):
+    pass
+
+
+class InvalidByMinute(ValidationError):
+    pass
+
+
+class InvalidByHour(ValidationError):
+    pass
+
+
+class InvalidByDay(ValidationError):
+    pass
+
+
+class InvalidByMonthDay(ValidationError):
+    pass
+
+
+class InvalidByWeekNumber(ValidationError):
+    pass
+
+
+class InvalidByYearDay(ValidationError):
+    pass
+
+
+class InvalidByMonth(ValidationError):
+    pass
+
+
+class InvalidBySetPosition(ValidationError):
+    pass
new file mode 100644
--- /dev/null
+++ b/tryton/health_caldav/security/access_rights.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0"?>
+<!-- This file is part of GNU Health.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+    <data>
+        <record model="res.group" id="group_calendar_admin">
+            <field name="name">Calendar Administration</field>
+        </record>
+        <record model="res.user-res.group"
+            id="user_admin_group_calendar_admin">
+            <field name="user" ref="res.user_admin"/>
+            <field name="group" ref="group_calendar_admin"/>
+        </record>
+
+<!--
+        <record model="res.user" id="user_trigger"> 
+            <field name="login">user_cron_trigger</field> 
+            <field name="name">Cron Trigger</field> 
+            <field name="active" eval="False"/> 
+
+        </record> 
+            <record model="res.user-res.group" id="user_trigger_group_admin"> 
+            <field name="user" ref="user_trigger"/> 
+            <field name="group" ref="group_calendar_admin"/> 
+        </record> 
+-->
+
+        <record model="ir.rule.group" id="rule_group_calendar_admin">
+            <field name="name">Calendar rule group</field>
+            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="False"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+
+        <record model="ir.rule" id="rule_group_calendar_admin_line1">
+            <field name="domain">[]</field>
+            <field name="rule_group" ref="rule_group_calendar_admin"/>
+        </record>
+        <record model="ir.rule.group-res.group"
+            id="rule_group_calendar_admin-calendar_admin">
+            <field name="rule_group" ref="rule_group_calendar_admin"/>
+            <field name="group" ref="group_calendar_admin"/>
+        </record>
+
+        <record model="ir.rule.group" id="rule_group_read_calendar">
+            <field name="name">Calendar rule group - read</field>
+            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="True"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.rule" id="rule_group_read_calendar_line1">
+            <field name="domain"
+                eval="[('owner', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_read_calendar"/>
+        </record>
+        <record model="ir.rule" id="rule_group_read_calendar_line2">
+            <field name="domain"
+                eval="[('read_users', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_read_calendar"/>
+        </record>
+
+        <record model="ir.rule.group" id="rule_group_write_calendar">
+            <field name="name">Calendar rule group - write</field>
+            <field name="model" search="[('model', '=', 'calendar.calendar')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="True"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+        <record model="ir.rule" id="rule_group_write_calendar_line1">
+            <field name="domain"
+                eval="[('owner', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_write_calendar"/>
+        </record>
+        <record model="ir.rule" id="rule_group_write_calendar_line2">
+            <field name="domain"
+                eval="[('write_users', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_write_calendar"/>
+        </record>
+        <record model="ir.rule.group" id="rule_group_event_admin">
+            <field name="name">Event rule group - admin</field>
+            <field name="model" search="[('model', '=', 'calendar.event')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="False"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+        <record model="ir.rule" id="rule_group_event_admin_line1">
+            <field name="domain" eval="[]" pyson="1"/>
+            <field name="rule_group" ref="rule_group_event_admin"/>
+        </record>
+        <record model="ir.rule.group-res.group"
+            id="rule_group_event_admin-calendar_admin">
+            <field name="rule_group" ref="rule_group_event_admin"/>
+            <field name="group" ref="group_calendar_admin"/>
+        </record>
+
+        <record model="ir.rule.group" id="rule_group_read_event">
+            <field name="name">Event rule group - read</field>
+            <field name="model" search="[('model', '=', 'calendar.event')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="True"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.rule" id="rule_group_read_event_line1">
+            <field name="domain"
+                eval="[('calendar.owner', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_read_event"/>
+        </record>
+        <record model="ir.rule" id="rule_group_read_event_line2">
+            <field name="domain"
+                eval="[('calendar.read_users', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_read_event"/>
+        </record>
+
+        <record model="ir.rule.group" id="rule_group_write_event">
+            <field name="name">Event rule group - write</field>
+            <field name="model" search="[('model', '=', 'calendar.event')]"/>
+            <field name="global_p" eval="False"/>
+            <field name="default_p" eval="True"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+        <record model="ir.rule" id="rule_group_write_event_line1">
+            <field name="domain"
+                eval="[('calendar.owner', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_write_event"/>
+        </record>
+        <record model="ir.rule" id="rule_group_write_event_line2">
+            <field name="domain"
+                eval="[('calendar.write_users', '=', Eval('user', {}).get('id', -1))]"
+                pyson="1"/>
+            <field name="rule_group" ref="rule_group_write_event"/>
+        </record>
+
+    </data>
+</tryton>
--- a/tryton/health_caldav/setup.py
+++ b/tryton/health_caldav/setup.py
@@ -49,11 +49,11 @@
     keywords='GNUHealth calendar caldav',
     package_dir={'trytond.modules.calendar': '.'},
     packages=[
-        'trytond.modules.calendar',
-        'trytond.modules.calendar.tests',
+        'trytond.modules.health_caldav',
+        'trytond.modules.health_caldav.tests',
         ],
     package_data={
-        'trytond.modules.calendar': (info.get('xml', [])
+        'trytond.modules.health_caldav': (info.get('xml', [])
             + ['tryton.cfg', 'view/*.xml', 'locale/*.po']),
         },
     classifiers=[
@@ -79,7 +79,7 @@
     zip_safe=False,
     entry_points="""
     [trytond.modules]
-    calendar = trytond.modules.calendar
+    calendar = trytond.modules.health_caldav
     """,
     test_suite='tests',
     test_loader='trytond.test_loader:Loader',
deleted file mode 100644
--- a/tryton/health_caldav/tests/scenario_calendar.py.bak
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/env python
-# This file is part of Tryton.  The COPYRIGHT file at the top level of
-# this repository contains the full copyright notices and license terms.
-from argparse import ArgumentParser
-from urlparse import urlparse
-import unittest
-import sys
-import datetime
-
-from dateutil.relativedelta import relativedelta
-import caldav
-import vobject
-from proteus import config, Model, Wizard
-
-
-def activate_module(name, config):
-    Module = Model.get('ir.module')
-    module, = Module.find([('name', '=', name)])
-    if module.state != 'activated':
-        Module.install([module.id], config.context)
-        Wizard('ir.module.activate_upgrade').execute('upgrade')
-
-
-def configure_user(login, config):
-    User = Model.get('res.user')
-    users = User.find([('login', '=', login)])
-    email = '%s@example.com' % login
-    if not users:
-        User(login=login, name=login, email=email).save()
-    else:
-        user, = users
-        user.email = email
-        user.save()
-
-
-def create_calendar(login, user, config):
-    Calendar = Model.get('calendar.calendar')
-    User = Model.get('res.user')
-    current_user, = User.find([('login', '=', login)])
-    main_user, = User.find([('login', '=', user)])
-    for calendar in Calendar.find([('owner', '=', login)]):
-        calendar.write_users.append(User(main_user.id))
-        calendar.save()
-        calendar.delete()
-    calendar = Calendar(name=login, owner=current_user)
-    if login != 'bar':
-        calendar.read_users.append(main_user)
-    calendar.save()
-
-
-class TestCase(unittest.TestCase):
-
-    def setUp(self):
-        self.client = caldav.DAVClient(URL)
-        self.principal = caldav.Principal(self.client, URL)
-        self.calendar, = [x for x in self.principal.calendars()
-            if x.url.path.endswith(user)]
-
-    def test0010calendar(self):
-        'Test calendar'
-        calendar, _ = self.principal.calendars()
-
-    def test0020create_event(self):
-        'Create event'
-        ical = vobject.iCalendar()
-        vevent = ical.add('vevent')
-        vevent.add('summary')
-        vevent.summary.value = 'Test event'
-        vevent.add('dtstart')
-        vevent.dtstart.value = (datetime.datetime.now()
-            + relativedelta(months=1))
-        vevent.add('dtend')
-        vevent.dtend.value = datetime.datetime.now() + relativedelta(months=1,
-            hours=1)
-        caldav.Event(self.client, data=ical.serialize(),
-            parent=self.calendar).save()
-
-    def test0030search_event(self):
-        'Search date'
-        events = self.calendar.date_search(datetime.datetime.now(),
-            datetime.datetime.now() + relativedelta(months=2))
-        self.assertEqual(len(events), 1)
-        events = self.calendar.date_search(
-            datetime.datetime.now() - relativedelta(months=1),
-            datetime.datetime.now())
-        self.assertEqual(len(events), 0)
-
-    def test0040get_event(self):
-        'Get event'
-        event = self.calendar.events()[0]
-        event.load()
-        self.assertEqual(event.url, self.calendar.event(event.id).url)
-
-    def test0050create_event_attendee(self):
-        'Create event with attendee'
-        ical = vobject.iCalendar()
-        vevent = ical.add('vevent')
-        vevent.add('summary')
-        vevent.summary.value = 'Test event with attendee'
-        vevent.add('dtstart')
-        vevent.dtstart.value = datetime.datetime.now() + relativedelta(days=10)
-        vevent.add('dtend')
-        vevent.dtend.value = datetime.datetime.now() + relativedelta(days=10,
-            hours=4)
-        vevent.add('organizer')
-        vevent.organizer.value = '%s@example.com' % user
-        attendees = []
-        for name in ('foo', 'bar'):
-            attendee = vobject.base.ContentLine('ATTENDEE', [], '')
-            attendee.partstat_param = 'TENTATIVE'
-            attendee.value = 'MAILTO:%s@example.com' % name
-            attendees.append(attendee)
-        vevent.attendee_list = attendees
-        caldav.Event(self.client, data=ical.serialize(),
-            parent=self.calendar).save()
-
-        Event = Model.get('calendar.event')
-        owner_event, = Event.find([
-                ('calendar.owner.email', '=', '%s@example.com' % user),
-                ('summary', '=', vevent.summary.value),
-                ])
-        attendee_event, = Event.find([
-                ('calendar.owner.email', '=', 'foo@example.com'),
-                ])
-        self.assertEqual(attendee_event.uuid, owner_event.uuid)
-
-    def test0060update_attendee_status(self):
-        'Update status of attendee'
-        for event in self.calendar.events():
-            event.load()
-            value = event.instance.vevent.summary.value
-            if value == 'Test event with attendee':
-                break
-        for attendee in event.instance.vevent.attendee_list:
-            attendee.partstat_param = 'accepted'
-        event.save()
-
-        Event = Model.get('calendar.event')
-        attendee_event, = Event.find([
-                ('calendar.owner.email', '=', 'foo@example.com'),
-                ])
-        for attendee in attendee_event.attendees:
-            self.assertEqual(attendee.status, 'accepted')
-
-    def test0070delete_attendee(self):
-        'Delete attendee'
-        for event in self.calendar.events():
-            event.load()
-            value = event.instance.vevent.summary.value
-            if value == 'Test event with attendee':
-                break
-        event.instance.vevent.attendee_list = []
-        event.save()
-
-        Event = Model.get('calendar.event')
-        self.assertEqual(Event.find([
-                    ('calendar.owner.email', '=', 'foo@example.com'),
-                    ]), [])
-
-if __name__ == '__main__':
-    parser = ArgumentParser()
-    parser.add_argument('--xmlrpc', dest='xmlrpc', metavar='URL',
-        help='use trytond XML-RPC at URL')
-    parser.add_argument('--url', dest='url', metavar='URL',
-        help='use calendar at URL')
-    options = parser.parse_args()
-    config = config.set_xmlrpc(options.xmlrpc)
-    xmlrpc_user = urlparse(options.xmlrpc).username
-    user = urlparse(options.url).username
-    assert xmlrpc_user == user
-    assert user != 'foo'
-    activate_module('calendar', config)
-    configure_user(user, config)
-    configure_user('foo', config)
-    configure_user('bar', config)
-    create_calendar(user, user, config)
-    create_calendar('foo', user, config)
-    create_calendar('bar', user, config)
-    URL = options.url
-    unittest.main(argv=sys.argv[:1])
--- a/tryton/health_caldav/tryton.cfg
+++ b/tryton/health_caldav/tryton.cfg
@@ -1,7 +1,8 @@
 [tryton]
 version=3.9.0
 depends:
-    webdav
+    health_webdav3_server
 xml:
     calendar.xml
+    security/access_rights.xml
     data/messages/messages.xml