From c87d58cabbcc145b8fd950332df4b4613a75a41f Mon Sep 17 00:00:00 2001 From: "rpa (Open ERP)" Date: Fri, 22 Jan 2010 19:25:53 +0530 Subject: [PATCH] [IMP,REF]: base_calendar, caldav: Improvement in import/export functionality and made function that import/export calendar with its event and task bzr revid: rpa@openerp.co.in-20100122135553-1tc8axr7y2abmpke --- addons/base_calendar/base_calendar.py | 132 ++++++++++++------ addons/base_calendar/base_calendar_data.xml | 96 ++++++------- addons/base_calendar/base_calendar_view.xml | 1 + addons/base_calendar/base_calendar_wizard.xml | 12 +- .../base_calendar/wizard/wizard_cal_export.py | 2 +- .../base_calendar/wizard/wizard_cal_import.py | 2 +- addons/caldav/caldav.py | 29 ++-- addons/caldav/caldav_data.xml | 4 +- addons/document_caldav/document_caldav.py | 3 +- .../project_calendar_data.xml | 3 +- 10 files changed, 173 insertions(+), 111 deletions(-) diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index fe4f0e45c50..51b761250c5 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -23,6 +23,7 @@ from datetime import datetime, timedelta from dateutil import parser from dateutil.rrule import * from osv import osv, fields +import base64 import pooler import re import vobject @@ -69,6 +70,8 @@ def get_attribute_mapping(cr, uid, calname, context={}): res[attr] = {} res[attr]['field'] = field.field_id.name res[attr]['type'] = field.field_id.ttype + if field.fn == 'hours': + res[attr]['type'] = "timedelta" if res[attr]['type'] in ('one2many', 'many2many', 'many2one'): res[attr]['object'] = field.field_id.relation elif res[attr]['type'] in ('selection') and field.mapping: @@ -154,12 +157,28 @@ class CalDAV(object): if self.__attribute__[name]: self.__attribute__[name][type] = None return True + + def parse_ics(self, cr, uid, child): + att_data = [] + for cal_data in child.getChildren(): + if cal_data.name.lower() == 'attendee': + attendee = self.pool.get('basic.calendar.attendee') + att_data.append(attendee.import_cal(cr, uid, cal_data)) + self.ical_set(cal_data.name.lower(), att_data, 'value') + continue + if cal_data.name.lower() == 'valarm': + alarm = self.pool.get('basic.calendar.alarm') + vals = alarm.import_cal(cr, uid, cal_data) + self.ical_set(cal_data.name.lower(), vals, 'value') + continue + if cal_data.name.lower() in self.__attribute__: + self.ical_set(cal_data.name.lower(), cal_data.value, 'value') + vals = map_data(cr, uid, self) + return vals - def export_ical(self, cr, uid, datas, vobj=None, context={}): - self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context) - ical = vobject.iCalendar() + def create_ics(self, cr, uid, datas, name, ical, context=None): for data in datas: - vevent = ical.add(vobj) + vevent = ical.add(name) for field in self.__attribute__.keys(): map_field = self.ical_get(field, 'field') map_type = self.ical_get(field, 'type') @@ -171,11 +190,11 @@ class CalDAV(object): uidval = openobjectid2uid(cr, data[map_field], model) model_obj = self.pool.get(model) cr.execute('select id from %s where recurrent_uid=%s' - % (model_obj._table, data[map_field])) + % (model_obj._table, data[map_field])) r_ids = map(lambda x: x[0], cr.fetchall()) if r_ids: rdata = self.pool.get(model).read(cr, uid, r_ids) - rcal = self.export_ical(cr, uid, rdata, context=context) + rcal = self.export_cal(cr, uid, rdata, context=context) for revents in rcal.contents['vevent']: ical.contents['vevent'].append(revents) if data.get('recurrent_uid', None): @@ -184,12 +203,12 @@ class CalDAV(object): elif field == 'attendee' and data[map_field]: model = self.__attribute__[field].get('object', False) attendee_obj = self.pool.get('basic.calendar.attendee') - vevent = attendee_obj.export_ical(cr, uid, model, \ + vevent = attendee_obj.export_cal(cr, uid, model, \ data[map_field], vevent, context=context) elif field == 'valarm' and data[map_field]: model = self.__attribute__[field].get('object', False) alarm_obj = self.pool.get('basic.calendar.alarm') - vevent = alarm_obj.export_ical(cr, uid, model, \ + vevent = alarm_obj.export_cal(cr, uid, model, \ data[map_field][0], vevent, context=context) elif data[map_field]: if map_type in ("char", "text"): @@ -212,29 +231,23 @@ class CalDAV(object): for key1, val1 in self.ical_get(field, 'mapping').items(): if val1 == data[map_field]: vevent.add(field).value = key1 + return vevent + + def export_cal(self, cr, uid, datas, vobj=None, context={}): + self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context) + ical = vobject.iCalendar() + self.create_ics(cr, uid, datas, vobj, ical, context=context) return ical - def import_ical(self, cr, uid, ical_data): + def import_cal(self, cr, uid, content, data_id=None, context=None): + ical_data = base64.decodestring(content) self.__attribute__ = get_attribute_mapping(cr, uid, self._calname) parsedCal = vobject.readOne(ical_data) att_data = [] res = [] for child in parsedCal.getChildren(): - for cal_data in child.getChildren(): - if cal_data.name.lower() == 'attendee': - attendee = self.pool.get('basic.calendar.attendee') - att_data.append(attendee.import_ical(cr, uid, cal_data)) - self.ical_set(cal_data.name.lower(), att_data, 'value') - continue - if cal_data.name.lower() == 'valarm': - alarm = self.pool.get('basic.calendar.alarm') - vals = alarm.import_ical(cr, uid, cal_data) - self.ical_set(cal_data.name.lower(), vals, 'value') - continue - if cal_data.name.lower() in self.__attribute__: - self.ical_set(cal_data.name.lower(), cal_data.value, 'value') if child.name.lower() in ('vevent', 'vtodo'): - vals = map_data(cr, uid, self) + vals = self.parse_ics(cr, uid, child) else: vals = {} continue @@ -245,7 +258,9 @@ class CalDAV(object): class Calendar(CalDAV, osv.osv): _name = 'basic.calendar' + _description = 'Calendar' _calname = 'calendar' + __attribute__ = { 'prodid': None, # Use: R-1, Type: TEXT, Specifies the identifier for the product that created the iCalendar object. 'version': None, # Use: R-1, Type: TEXT, Specifies the identifier corresponding to the highest version number @@ -268,24 +283,61 @@ class Calendar(CalDAV, osv.osv): _defaults = { 'active': lambda *a: True, } - -Calendar() + def export_cal(self, cr, uid, datas, vobj='vevent', context={}): + cal = self.browse(cr, uid, datas[0]) + ical = vobject.iCalendar() + for line in cal.line_ids: + if line.name in ('alarm', 'attendee'): + continue + mod_obj = self.pool.get(line.object_id.model) + data_ids = mod_obj.search(cr, uid, eval(line.domain), context=context) + datas = mod_obj.read(cr, uid, data_ids, context=context) + context.update({'model': line.object_id.model}) + self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context) + self.create_ics(cr, uid, datas, line.name, ical, context=context) + return ical.serialize() + + def import_cal(self, cr, uid, content, data_id=None, context=None): + ical_data = base64.decodestring(content) + parsedCal = vobject.readOne(ical_data) + if not data_id: + data_id = self.search(cr, uid, [])[0] + cal = self.browse(cr, uid, data_id) + cal_children = {} + count = 0 + for line in cal.line_ids: + cal_children[line.name] = line.object_id.model + for child in parsedCal.getChildren(): + if child.name.lower() in cal_children: + self.__attribute__ = get_attribute_mapping(cr, uid, child.name.lower()) + val = self.parse_ics(cr, uid, child) + obj = self.pool.get(cal_children[child.name.lower()]) + if hasattr(obj, 'check_import'): + obj.check_import(cr, uid, [val], context={}) + return {} + +Calendar() class basic_calendar_line(osv.osv): _name = 'basic.calendar.lines' - _description = 'Calendar Lines' + _description = 'Calendar Lines' _columns = { - 'name': fields.selection([('event', 'Event'), ('todo', 'TODO'), \ + 'name': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \ ('alarm', 'Alarm'), \ ('attendee', 'Attendee')], \ string="Type", size=64), 'object_id': fields.many2one('ir.model', 'Object'), 'calendar_id': fields.many2one('basic.calendar', 'Calendar', \ - required=True, ondelete='cascade',), + required=True, ondelete='cascade'), + 'domain': fields.char('Domain', size=124), 'mapping_ids': fields.one2many('basic.calendar.fields', 'type_id', 'Fields Mapping') } + _defaults = { + 'domain': lambda *a: '[]', + } + basic_calendar_line() class basic_calendar_attribute(osv.osv): @@ -293,7 +345,7 @@ class basic_calendar_attribute(osv.osv): _description = 'Calendar attributes' _columns = { 'name': fields.char("Name", size=64, required=True), - 'type': fields.selection([('event', 'Event'), ('todo', 'TODO'), \ + 'type': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \ ('alarm', 'Alarm'), \ ('attendee', 'Attendee')], \ string="Type", size=64, required=True), @@ -321,12 +373,12 @@ class basic_calendar_fields(osv.osv): _defaults = { 'fn': lambda *a: 'field', } - + basic_calendar_fields() class Event(CalDAV, osv.osv_memory): _name = 'basic.calendar.event' - _calname = 'event' + _calname = 'vevent' __attribute__ = { 'class': None, # Use: O-1, Type: TEXT, Defines the access classification for a calendar component like "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" 'created': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the calendar information was created by the calendar user agent in the calendar store. @@ -362,14 +414,14 @@ class Event(CalDAV, osv.osv_memory): 'duration': None, # Use: O-1, Type: DURATION, Specifies a positive duration of time. 'dtend': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends. } - def export_ical(self, cr, uid, datas, vobj='vevent', context={}): - return super(Event, self).export_ical(cr, uid, datas, 'vevent', context=context) + def export_cal(self, cr, uid, datas, vobj='vevent', context={}): + return super(Event, self).export_cal(cr, uid, datas, 'vevent', context=context) Event() class ToDo(CalDAV, osv.osv_memory): _name = 'basic.calendar.todo' - _calname = 'todo' + _calname = 'vtodo' __attribute__ = { 'class': None, @@ -406,8 +458,8 @@ class ToDo(CalDAV, osv.osv_memory): 'rrule': None, } - def export_ical(self, cr, uid, datas, vobj='vevent', context={}): - return super(ToDo, self).export_ical(cr, uid, datas, 'vtodo', context=context) + def export_cal(self, cr, uid, datas, vobj='vevent', context={}): + return super(ToDo, self).export_cal(cr, uid, datas, 'vtodo', context=context) ToDo() @@ -460,7 +512,7 @@ class Alarm(CalDAV, osv.osv_memory): 'x-prop': None, } - def export_ical(self, cr, uid, model, alarm_id, vevent, context={}): + def export_cal(self, cr, uid, model, alarm_id, vevent, context={}): valarm = vevent.add('valarm') alarm_object = self.pool.get(model) alarm_data = alarm_object.read(cr, uid, alarm_id, []) @@ -486,7 +538,7 @@ class Alarm(CalDAV, osv.osv_memory): valarm.add('ACTION').value = alarm_data['action'] return vevent - def import_ical(self, cr, uid, ical_data): + def import_cal(self, cr, uid, ical_data): for child in ical_data.getChildren(): if child.name.lower() == 'trigger': seconds = child.value.seconds @@ -536,7 +588,7 @@ class Attendee(CalDAV, osv.osv_memory): 'language': None, # Use: 0-1 Specify the language for text values in a property or property parameter. } - def import_ical(self, cr, uid, ical_data): + def import_cal(self, cr, uid, ical_data): for para in ical_data.params: if para.lower() == 'cn': self.ical_set(para.lower(), ical_data.params[para][0]+':'+ \ @@ -548,7 +600,7 @@ class Attendee(CalDAV, osv.osv_memory): vals = map_data(cr, uid, self) return vals - def export_ical(self, cr, uid, model, attendee_ids, vevent, context={}): + def export_cal(self, cr, uid, model, attendee_ids, vevent, context={}): attendee_object = self.pool.get(model) self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context) for attendee in attendee_object.read(cr, uid, attendee_ids, []): diff --git a/addons/base_calendar/base_calendar_data.xml b/addons/base_calendar/base_calendar_data.xml index 0eb232ac0a3..0e7250071c8 100644 --- a/addons/base_calendar/base_calendar_data.xml +++ b/addons/base_calendar/base_calendar_data.xml @@ -10,137 +10,137 @@ comment - event + vevent uid - event + vevent seq - event + vevent recurrence-id - event + vevent transp - event + vevent attendee - event + vevent related - event + vevent rrule - event + vevent dtend - event + vevent valarm - event + vevent priority - event + vevent location - event + vevent exrule - event + vevent resources - event + vevent rstatus - event + vevent status - event + vevent exdate - event + vevent dtstamp - event + vevent description - event + vevent rdate - event + vevent dtstart - event + vevent class - event + vevent x-openobject-model - event + vevent created - event + vevent url - event + vevent summary - event + vevent contact - event + vevent @@ -148,107 +148,107 @@ status - todo + vtodo comment - todo + vtodo attendee - todo + vtodo valarm - todo + vtodo description - todo + vtodo seq - todo + vtodo url - todo + vtodo completed - todo + vtodo percent - todo + vtodo due - todo + vtodo summary - todo + vtodo priority - todo + vtodo exdate - todo + vtodo location - todo + vtodo exrule - todo + vtodo duration - todo + vtodo organizer - todo + vtodo dtstart - todo + vtodo rrule - todo + vtodo class - todo + vtodo uid - todo + vtodo diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml index f054fc5471d..0165e483f53 100644 --- a/addons/base_calendar/base_calendar_view.xml +++ b/addons/base_calendar/base_calendar_view.xml @@ -14,6 +14,7 @@
+ diff --git a/addons/base_calendar/base_calendar_wizard.xml b/addons/base_calendar/base_calendar_wizard.xml index 153b490750c..1c20f80a06c 100644 --- a/addons/base_calendar/base_calendar_wizard.xml +++ b/addons/base_calendar/base_calendar_wizard.xml @@ -1,19 +1,19 @@ - + - + - + \ No newline at end of file diff --git a/addons/base_calendar/wizard/wizard_cal_export.py b/addons/base_calendar/wizard/wizard_cal_export.py index 8431e9d1c71..f0504b3a6b6 100644 --- a/addons/base_calendar/wizard/wizard_cal_export.py +++ b/addons/base_calendar/wizard/wizard_cal_export.py @@ -52,7 +52,7 @@ class cal_event_export_wizard(wizard.interface): calendar = model_obj.export_cal(cr, uid, data['ids'], context) return {'file_path': base64.encodestring(calendar), \ 'name': 'OpenERP %s.ics' % (model_obj._description)} - + states = { 'init': { 'actions': [_process_export_ics], diff --git a/addons/base_calendar/wizard/wizard_cal_import.py b/addons/base_calendar/wizard/wizard_cal_import.py index d7295f9ce53..fac1eaeab4d 100644 --- a/addons/base_calendar/wizard/wizard_cal_import.py +++ b/addons/base_calendar/wizard/wizard_cal_import.py @@ -54,7 +54,7 @@ class cal_event_import_wizard(wizard.interface): def _process_imp_ics(self, cr, uid, data, context=None): model = data.get('model') model_obj = pooler.get_pool(cr.dbname).get(model) - vals = model_obj.import_cal(cr, uid, data['form']['file_path'], context) + vals = model_obj.import_cal(cr, uid, data['form']['file_path'], data['id'], context) global cnt cnt = 0 if vals: diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py index c11110609a8..0e8c1164289 100644 --- a/addons/caldav/caldav.py +++ b/addons/caldav/caldav.py @@ -482,15 +482,17 @@ rule or repeating pattern for anexception to a recurrence set"), ids = map(lambda x: caldav_id2real_id(x), ids) event_data = self.read(cr, uid, ids) event_obj = self.pool.get('basic.calendar.event') - ical = event_obj.export_ical(cr, uid, event_data, context={'model': self._name}) + ical = event_obj.export_cal(cr, uid, event_data, context={'model': self._name}) cal_val = ical.serialize() cal_val = cal_val.replace('"', '').strip() return cal_val - def import_cal(self, cr, uid, data, context={}): - file_content = base64.decodestring(data) + def import_cal(self, cr, uid, data, data_id=None, context={}): event_obj = self.pool.get('basic.calendar.event') - vals = event_obj.import_ical(cr, uid, file_content) + vals = event_obj.import_cal(cr, uid, data) + return self.check_import(cr, uid, vals, context=context) + + def check_import(self, cr, uid, vals, context={}): ids = [] for val in vals: exists, r_id = base_calendar.uid2openobjectid(cr, val['id'], self._name, \ @@ -509,7 +511,7 @@ rule or repeating pattern for anexception to a recurrence set"), event_id = self.create(cr, uid, val) ids.append(event_id) return ids - + def modify_this(self, cr, uid, ids, defaults, context=None, *args): datas = self.read(cr, uid, ids[0], context=context) date = datas.get('date') @@ -727,10 +729,13 @@ class calendar_todo(osv.osv): __attribute__ = {} - def import_cal(self, cr, uid, data, context={}): - file_content = base64.decodestring(data) + def import_cal(self, cr, uid, data, data_id=None, context={}): todo_obj = self.pool.get('basic.calendar.todo') - vals = todo_obj.import_ical(cr, uid, file_content) + vals = todo_obj.import_cal(cr, uid, data) + return self.check_import(cr, uid, vals, context=context) + + def check_import(self, cr, uid, vals, context={}): + ids = [] for val in vals: obj_tm = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.project_time_mode_id if not val.has_key('planned_hours'): @@ -749,10 +754,12 @@ class calendar_todo(osv.osv): val.pop('id') if exists: self.write(cr, uid, [exists], val) + ids.append(exists) else: task_id = self.create(cr, uid, val) - return {'count': len(vals)} - + ids.append(task_id) + return ids + def export_cal(self, cr, uid, ids, context={}): task_datas = self.read(cr, uid, ids, [], context ={'read': True}) tasks = [] @@ -761,7 +768,7 @@ class calendar_todo(osv.osv): task.pop('planned_hours') tasks.append(task) todo_obj = self.pool.get('basic.calendar.todo') - ical = todo_obj.export_ical(cr, uid, tasks, context={'model': self._name}) + ical = todo_obj.export_cal(cr, uid, tasks, context={'model': self._name}) calendar_val = ical.serialize() calendar_val = calendar_val.replace('"', '').strip() return calendar_val diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml index e32ec1a663a..fb464ab95d7 100644 --- a/addons/caldav/caldav_data.xml +++ b/addons/caldav/caldav_data.xml @@ -131,13 +131,13 @@ - event + vevent - todo + vtodo diff --git a/addons/document_caldav/document_caldav.py b/addons/document_caldav/document_caldav.py index 4f266e44c63..01af5d0d345 100644 --- a/addons/document_caldav/document_caldav.py +++ b/addons/document_caldav/document_caldav.py @@ -36,8 +36,9 @@ class document_directory_content(osv.osv): return super(document_directory_content, self).process_write(cr, uid, node, data, context) content = self.browse(cr, uid, node.cnt_id, context) fobj = self.pool.get(content.object_id.model) + if not context: + context = {} fobj.import_cal(cr, uid, base64.encodestring(data), context=context) - return True def process_read(self, cr, uid, node, context=None): diff --git a/addons/project_calendar/project_calendar_data.xml b/addons/project_calendar/project_calendar_data.xml index 5b371611a55..b78931381b3 100644 --- a/addons/project_calendar/project_calendar_data.xml +++ b/addons/project_calendar/project_calendar_data.xml @@ -6,11 +6,12 @@ + {'needs-action': 'draft', 'completed': 'done', 'in-process': 'open', 'cancelled': 'cancelled'} field - + field