Mercurial > hgweb > health
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])
