X-Git-Url: http://git.inspyration.org/?a=blobdiff_plain;f=addons%2Fcaldav%2Fcalendar.py;h=a70a31bc0177d16bf159bf210c387811ba2efdf4;hb=4506d1d2d25662a05f002a847e663d0880ffc61f;hp=9ca6b924e4dfad9b20ecba13e97c3df735278b02;hpb=305b48abe3195f3a7d93852637c79228885d01a2;p=odoo%2Fodoo.git diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index 9ca6b92..a70a31b 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -38,8 +38,7 @@ from tools.safe_eval import safe_eval as eval try: import vobject except ImportError: - raise osv.except_osv('vobject Import Error!','Please install python-vobject \ - from http://vobject.skyhouseconsulting.com/') + raise osv.except_osv(_('vobject Import Error!'), _('Please install python-vobject from http://vobject.skyhouseconsulting.com/')) # O-1 Optional and can come only once # O-n Optional and can come more than once @@ -149,7 +148,7 @@ def get_attribute_mapping(cr, uid, calname, context=None): @param calname: Get Calendar name @param context: A standard dictionary for contextual values """ - if not context: + if context is None: context = {} pool = pooler.get_pool(cr.dbname) field_obj = pool.get('basic.calendar.fields') @@ -160,11 +159,13 @@ def get_attribute_mapping(cr, uid, calname, context=None): type_id = type_obj.search(cr, uid, domain) fids = field_obj.search(cr, uid, [('type_id', '=', type_id[0])]) res = {} - for field in field_obj.browse(cr, uid, fids): + for field in field_obj.browse(cr, uid, fids, context=context): attr = field.name.name res[attr] = {} res[attr]['field'] = field.field_id.name res[attr]['type'] = field.field_id.ttype + if field.fn == 'datetime_utc': + res[attr]['type'] = 'utc' if field.fn == 'hours': res[attr]['type'] = "timedelta" if res[attr]['type'] in ('one2many', 'many2many', 'many2one'): @@ -255,7 +256,6 @@ class CalDAV(object): @param name: Get Attribute Name @param type: Get Attribute Type """ - if self.__attribute__.get(name): val = self.__attribute__.get(name).get(type, None) valtype = self.__attribute__.get(name).get('type', None) @@ -274,7 +274,6 @@ class CalDAV(object): @param self: The object pointer, @param type: Get Attribute Type """ - for name in self.__attribute__: if self.__attribute__[name]: self.__attribute__[name][type] = None @@ -447,6 +446,21 @@ class CalDAV(object): dtfield.value = self.format_date_tz(parser.parse(data[map_field]), tzval.title()) else: dtfield.value = parser.parse(data[map_field]) + + elif map_type == 'utc'and data[map_field]: + if tzval: + local = pytz.timezone (tzval.title()) + naive = datetime.strptime (data[map_field], "%Y-%m-%d %H:%M:%S") + local_dt = naive.replace (tzinfo = local) + utc_dt = local_dt.astimezone (pytz.utc) + vevent.add(field).value = utc_dt + else: + utc_timezone = pytz.timezone ('UTC') + naive = datetime.strptime (data[map_field], "%Y-%m-%d %H:%M:%S") + local_dt = naive.replace (tzinfo = utc_timezone) + utc_dt = local_dt.astimezone (pytz.utc) + vevent.add(field).value = utc_dt + elif map_type == "timedelta": vevent.add(field).value = timedelta(hours=data[map_field]) elif map_type == "many2one": @@ -470,7 +484,7 @@ class CalDAV(object): @param vals: Get Values @param context: A standard dictionary for contextual values """ - if not context: + if context is None: context = {} ids = [] model_obj = self.pool.get(context.get('model')) @@ -580,8 +594,8 @@ class Calendar(CalDAV, osv.osv): string="Type", size=64), 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date', readonly=True), - 'write_date': fields.datetime('Modifided Date', readonly=True), - 'description': fields.text("description"), + 'write_date': fields.datetime('Write Date', readonly=True), + 'description': fields.text("Description"), 'calendar_color': fields.char('Color', size=20, help="For supporting clients, the color of the calendar entries"), 'calendar_order': fields.integer('Order', help="For supporting clients, the order of this folder among the calendars"), 'has_webcal': fields.boolean('WebCal', required=True, help="Also export a .ics entry next to the calendar folder, with WebCal content."), @@ -592,7 +606,7 @@ class Calendar(CalDAV, osv.osv): } def get_calendar_objects(self, cr, uid, ids, parent=None, domain=None, context=None): - if not context: + if context is None: context = {} if not domain: domain = [] @@ -622,7 +636,7 @@ class Calendar(CalDAV, osv.osv): def get_cal_max_modified(self, cr, uid, ids, parent=None, domain=None, context=None): - if not context: + if context is None: context = {} if not domain: domain = [] @@ -652,12 +666,12 @@ class Calendar(CalDAV, osv.osv): @param vobj: the type of object to export @return the ical data. """ - if not context: + if context is None: context = {} ctx_model = context.get('model', None) ctx_res_id = context.get('res_id', None) ical = vobject.iCalendar() - for cal in self.browse(cr, uid, ids): + for cal in self.browse(cr, uid, ids, context=context): for line in cal.line_ids: if ctx_model and ctx_model != line.object_id.model: continue @@ -684,7 +698,7 @@ class Calendar(CalDAV, osv.osv): @param data_id: Get Data’s ID or False @param context: A standard dictionary for contextual values """ - if not context: + if context is None: context = {} vals = [] ical_data = content @@ -770,12 +784,35 @@ class basic_calendar_line(osv.osv): res = cr.fetchone() if res: if res[0] > 0: - raise osv.except_osv(_('Warning !'), _('Can not create \ -line "%s" more than once' % (vals.get('name')))) + raise osv.except_osv(_('Warning !'), _('Can not create line "%s" more than once') % (vals.get('name'))) return super(basic_calendar_line, self).create(cr, uid, vals, context=context) basic_calendar_line() +class basic_calendar_alias(osv.osv): + """ Mapping of client filenames to ORM ids of calendar records + + Since some clients insist on putting arbitrary filenames on the .ics data + they send us, and they won't respect the redirection "Location:" header, + we have to store those filenames and allow clients to call our calendar + records with them. + Note that adding a column to all tables that would possibly hold calendar- + mapped data won't work. The user is always allowed to specify more + calendars, on any arbitrary ORM object, without need to alter those tables' + data or structure + """ + _name = 'basic.calendar.alias' + _columns = { + 'name': fields.char('Filename', size=512, required=True, select=1), + 'cal_line_id': fields.many2one('basic.calendar.lines', 'Calendar', required=True, + select=1, help='The calendar/line this mapping applies to'), + 'res_id': fields.integer('Res. ID', required=True, select=1), + } + + _sql_constraints = [ ('name_cal_uniq', 'UNIQUE(cal_line_id, name)', + _('The same filename cannot apply to two records!')), ] + +basic_calendar_alias() class basic_calendar_attribute(osv.osv): _name = 'basic.calendar.attributes' @@ -796,6 +833,7 @@ class basic_calendar_fields(osv.osv): _name = 'basic.calendar.fields' _description = 'Calendar fields' + _order = 'name' _columns = { 'field_id': fields.many2one('ir.model.fields', 'OpenObject Field'), @@ -806,12 +844,13 @@ class basic_calendar_fields(osv.osv): 'fn': fields.selection([('field', 'Use the field'), ('const', 'Expression as constant'), ('hours', 'Interval in hours'), + ('datetime_utc', 'Datetime In UTC'), ], 'Function'), 'mapping': fields.text('Mapping'), } _defaults = { - 'fn': lambda *a: 'field', + 'fn': 'field', } _sql_constraints = [ @@ -835,7 +874,7 @@ class basic_calendar_fields(osv.osv): line = line_obj.browse(cr, uid, l_id, context=context)[0] line_rel = line.object_id.model if (relation != 'NULL') and (not relation == line_rel): - raise osv.except_osv(_('Warning !'), _('Please provide proper configuration of "%s" in Calendar Lines' % (name))) + raise osv.except_osv(_('Warning !'), _('Please provide proper configuration of "%s" in Calendar Lines') % (name)) return True def create(self, cr, uid, vals, context=None): @@ -1043,7 +1082,7 @@ class Timezone(CalDAV, osv.osv_memory): @param model: Get Model's name @param context: A standard dictionary for contextual values """ - if not context: + if context is None: context = {} ctx = context.copy() ctx.update({'model': model}) @@ -1102,8 +1141,6 @@ class Alarm(CalDAV, osv.osv_memory): @param alarm_id: Get Alarm's Id @param context: A standard dictionary for contextual values """ - if not context: - context = {} valarm = vevent.add('valarm') alarm_object = self.pool.get(model) alarm_data = alarm_object.read(cr, uid, alarm_id, []) @@ -1137,17 +1174,23 @@ class Alarm(CalDAV, osv.osv_memory): @param ical_data: Get calendar's Data @param context: A standard dictionary for contextual values """ - + if context is None: + context = {} ctx = context.copy() ctx.update({'model': context.get('model', None)}) self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx) for child in ical_data.getChildren(): if child.name.lower() == 'trigger': - seconds = child.value.seconds - days = child.value.days - diff = (days * 86400) + seconds - interval = 'days' - related = 'before' + if isinstance(child.value, timedelta): + seconds = child.value.seconds + days = child.value.days + diff = (days * 86400) + seconds + interval = 'days' + related = 'before' + elif isinstance(child.value, datetime): + # TODO + # remember, spec says this datetime is in UTC + raise NotImplementedError("we cannot parse absolute triggers") if not seconds: duration = abs(days) related = days > 0 and 'after' or 'before' @@ -1199,7 +1242,8 @@ class Attendee(CalDAV, osv.osv_memory): @param ical_data: Get calendar's Data @param context: A standard dictionary for contextual values """ - + if context is None: + context = {} ctx = context.copy() ctx.update({'model': context.get('model', None)}) self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx) @@ -1223,7 +1267,7 @@ class Attendee(CalDAV, osv.osv_memory): @param attendee_ids: Get Attendee's Id @param context: A standard dictionary for contextual values """ - if not context: + if context is None: context = {} attendee_object = self.pool.get(model) ctx = context.copy()