import re
import tools
import time
+import logging
from caldav_node import res_node_calendar
+from orm_utils import get_last_modified
+from tools.safe_eval import safe_eval as eval
try:
import vobject
model_obj = pooler.get_pool(cr.dbname).get(model)
if (not model == oomodel) or (not dbname == cr.dbname):
return (False, None)
- qry = 'select distinct(id) from %s' % model_obj._table
+ qry = 'SELECT DISTINCT(id) FROM %s' % model_obj._table
if rdate:
- qry += " where recurrent_id='%s'" % (rdate)
- cr.execute(qry)
+ qry += " WHERE recurrent_id=%s"
+ cr.execute(qry, (rdate,))
r_id = cr.fetchone()
if r_id:
return (id, r_id[0])
+ else:
+ return (False, None)
cr.execute(qry)
ids = map(lambda x: str(x[0]), cr.fetchall())
if id in ids:
args = [arg,]
else:
args = arg
-
+
for ard in args:
rstr = ard.get('name','')
if ard.get('company',False):
"""
# TODO: move to tools or sth.
mege = re.compile(r'([^\(\<]+) *(\((.*?)\))? *(\< ?(.*?) ?\>)? ?(\((.*?)\))? *$')
-
+
mailz= [emailstr,]
retz = []
if multi:
mailz = emailstr.split(',')
-
+
for mas in mailz:
m = mege.match(mas.strip())
if not m:
# retz.append({ 'name': mas.strip() })
# continue
raise ValueError("Invalid email address %r" % mas)
- rd = { 'name': m.group(1).strip(),
+ rd = { 'name': m.group(1).strip(),
'email': m.group(5), }
if m.group(2):
rd['company'] = m.group(3).strip()
elif m.group(6):
rd['company'] = m.group(7).strip()
-
+
if rd['name'].startswith('"') and rd['name'].endswith('"'):
rd['name'] = rd['name'][1:-1]
retz.append(rd)
-
+
if multi:
return retz
else:
if field_type == 'selection':
if not map_val:
continue
+ if type(map_val) == list and len(map_val): #TOFIX: why need to check this
+ map_val = map_val[0]
mapping = obj.__attribute__[map_dict].get('mapping', False)
if mapping:
map_val = mapping.get(map_val.lower(), False)
class CalDAV(object):
__attribute__ = {}
-
-
+ _logger = logging.getLogger('document.caldav')
def ical_set(self, name, value, type):
""" set calendar Attribute
att_data = []
exdates = []
_server_tzinfo = pytz.timezone(tools.get_server_timezone())
-
+
for cal_data in child.getChildren():
if cal_data.name.lower() == 'organizer':
dmail = { 'name': cal_data.params.get('CN', ['',])[0],
- 'email': cal_data.value.replace('MAILTO:',''),
+ 'email': cal_data.value.lower().replace('mailto:',''),
# TODO: company?
- }
+ }
self.ical_set(cal_data.name.lower(), mailto2str(dmail), 'value')
continue
if cal_data.name.lower() == 'attendee':
if cal_data.name.lower() in self.__attribute__:
if cal_data.params.get('X-VOBJ-ORIGINAL-TZID'):
self.ical_set('vtimezone', cal_data.params.get('X-VOBJ-ORIGINAL-TZID'), 'value')
- date_utc = cal_data.value.astimezone(pytz.utc)
- self.ical_set(cal_data.name.lower(), date_utc, 'value')
+ date_local = cal_data.value.astimezone(_server_tzinfo)
+ self.ical_set(cal_data.name.lower(), date_local, 'value')
continue
self.ical_set(cal_data.name.lower(), cal_data.value, 'value')
vals = map_data(cr, uid, self, context=context)
model_obj = self.pool.get(model)
r_ids = []
if model_obj._columns.get('recurrent_uid', None):
- cr.execute('select id from %s where recurrent_uid=%s'
- % (model_obj._table, data[map_field]))
+ cr.execute('SELECT id FROM %s WHERE recurrent_uid=%%s' % model_obj._table,
+ (data[map_field],))
r_ids = map(lambda x: x[0], cr.fetchall())
if r_ids:
r_datas = model_obj.read(cr, uid, r_ids, context=context)
else:
for key1, val1 in self.ical_get(field, 'mapping').items():
if val1 == data[map_field]:
- vevent.add(field).value = key1
+ vevent.add(field).value = key1.upper()
return vevent
def check_import(self, cr, uid, vals, context=None):
ical = vobject.iCalendar()
self.create_ics(cr, uid, datas, vobj, ical, context=context)
return ical
- except Exception, e:
+ except:
raise # osv.except_osv(('Error !'), (str(e)))
def import_cal(self, cr, uid, content, data_id=None, context=None):
'create_date': fields.datetime('Created Date', readonly=True),
'write_date': fields.datetime('Modifided Date', readonly=True),
'description': fields.text("description"),
+ 'calendar_color': fields.char('Color', size=20, help="For supporting clients, the color of the calendar entries"),
+ 'calendar_order': fields.integer('Order', help="For supporting clients, the order of this folder among the calendars"),
+ 'has_webcal': fields.boolean('WebCal', required=True, help="Also export a <name>.ics entry next to the calendar folder, with WebCal content."),
+ }
+
+ _defaults = {
+ 'has_webcal': False,
}
def get_calendar_objects(self, cr, uid, ids, parent=None, domain=None, context=None):
continue
if line.name in ('valarm', 'attendee'):
continue
- line_domain = eval(line.domain or '[]')
+ line_domain = eval(line.domain or '[]', context)
line_domain += domain
if ctx_res_id:
line_domain += [('id','=',ctx_res_id)]
data_ids = mod_obj.search(cr, uid, line_domain, order="id", context=context)
for data in mod_obj.browse(cr, uid, data_ids, context):
ctx = parent and parent.context or None
- if data.recurrent_uid:
+ if hasattr(data, 'recurrent_uid') and data.recurrent_uid:
# Skip for event which is child of other event
continue
node = res_node_calendar('%s.ics' %data.id, parent, ctx, data, line.object_id.model, data.id)
res.append(node)
return res
+
+
+ def get_cal_max_modified(self, cr, uid, ids, parent=None, domain=None, context=None):
+ if not context:
+ context = {}
+ if not domain:
+ domain = []
+ res = None
+ ctx_res_id = context.get('res_id', None)
+ ctx_model = context.get('model', None)
+ for cal in self.browse(cr, uid, ids):
+ for line in cal.line_ids:
+ if ctx_model and ctx_model != line.object_id.model:
+ continue
+ if line.name in ('valarm', 'attendee'):
+ continue
+ line_domain = eval(line.domain or '[]', context)
+ line_domain += domain
+ if ctx_res_id:
+ line_domain += [('id','=',ctx_res_id)]
+ mod_obj = self.pool.get(line.object_id.model)
+ max_data = get_last_modified(mod_obj, cr, uid, line_domain, context=context)
+ if res and res > max_data:
+ continue
+ res = max_data
+ return res
def export_cal(self, cr, uid, ids, vobj='vevent', context=None):
""" Export Calendar
continue
if line.name in ('valarm', 'attendee'):
continue
- domain = eval(line.domain or '[]')
+ domain = eval(line.domain or '[]', context)
if ctx_res_id:
domain += [('id','=',ctx_res_id)]
mod_obj = self.pool.get(line.object_id.model)
data_id = self.search(cr, uid, [])[0]
cal = self.browse(cr, uid, data_id, context=context)
cal_children = {}
- count = 0
+
for line in cal.line_ids:
cal_children[line.name] = line.object_id.model
objs = []
val = self.parse_ics(cr, uid, child, cal_children=cal_children, context=context)
vals.append(val)
objs.append(cal_children[child.name.lower()])
+ elif child.name.upper() == 'CALSCALE':
+ if child.value.upper() != 'GREGORIAN':
+ self._logger.warning('How do I handle %s calendars?',child.value)
+ elif child.name.upper() in ('PRODID', 'VERSION'):
+ pass
+ elif child.name.upper().startswith('X-'):
+ self._logger.debug("skipping custom node %s", child.name)
+ else:
+ self._logger.debug("skipping node %s", child.name)
res = []
for obj_name in list(set(objs)):
@param context: A standard dictionary for contextual values
"""
- cr.execute("Select count(id) from basic_calendar_lines \
- where name='%s' and calendar_id=%s" % (vals.get('name'), vals.get('calendar_id')))
+ cr.execute("SELECT COUNT(id) FROM basic_calendar_lines \
+ WHERE name=%s AND calendar_id=%s",
+ (vals.get('name'), vals.get('calendar_id')))
res = cr.fetchone()
if res:
if res[0] > 0:
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'
@param context: A standard dictionary for contextual values
"""
- cr.execute('select name from basic_calendar_attributes \
- where id=%s' % (vals.get('name')))
+ cr.execute('SELECT name FROM basic_calendar_attributes \
+ WHERE id=%s', (vals.get('name'),))
name = cr.fetchone()
name = name[0]
if name in ('valarm', 'attendee'):