[ADD]: Images: caldav, crm_caldav, document_webdav, project_caldav
[odoo/odoo.git] / addons / caldav / caldav_node.py
index f104b27..5272d0f 100644 (file)
 #
 ##############################################################################
 
-import time
 from document_webdav import nodes
-from document.nodes import _str2time
+from document.nodes import _str2time, nodefd_static
 import logging
-import StringIO
 from orm_utils import get_last_modified
 
-from tools.dict_tools import dict_merge, dict_merge2
+try:
+    from tools.dict_tools import  dict_merge2
+except ImportError:
+    from document.dict_tools import  dict_merge2
 
 # TODO: implement DAV-aware errors, inherit from IOError
 
@@ -65,6 +66,9 @@ class node_calendar_collection(nodes.node_dir):
         for cal in fil_obj.browse(cr, uid, ids, context=ctx):
             if (not name) or not ext:
                 res.append(node_calendar(cal.name, self, self.context, cal))
+            if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+                # these ones must not see the webcal entry.
+                continue
             if cal.has_webcal and (not name) or ext:
                 res.append(res_node_calendar(cal.name+'.ics', self, self.context, cal))
             # May be both of them!
@@ -120,6 +124,9 @@ class node_calendar_res_col(nodes.node_res_obj):
         for cal in fil_obj.browse(cr, uid, ids, context=ctx):
             if (not name) or not ext:
                 res.append(node_calendar(cal.name, self, self.context, cal))
+            if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+                # these ones must not see the webcal entry.
+                continue
             if cal.has_webcal and (not name) or ext:
                 res.append(res_node_calendar(cal.name+'.ics', self, self.context, cal))
             # May be both of them!
@@ -206,8 +213,9 @@ class node_calendar(nodes.node_class):
     def get_dav_resourcetype(self, cr):
         res = [ ('collection', 'DAV:'),
                 ('calendar', 'urn:ietf:params:xml:ns:caldav'),
-                (str(self.cal_type + '-collection'), 'http://groupdav.org/'),
                 ]
+        if self.context.get('DAV-client', '') == 'GroupDAV':
+            res.append((str(self.cal_type + '-collection'), 'http://groupdav.org/'))
         return res
 
     def get_domain(self, cr, filters):
@@ -253,22 +261,9 @@ class node_calendar(nodes.node_class):
                     _log.debug("Unknown calendar-query element: %s", filter_child.localName)
             return res
         elif filters.localName == 'calendar-multiget':
-            names = []
-            for filter_child in filters.childNodes:
-                if filter_child.nodeType == filter_child.TEXT_NODE:
-                    continue
-                if filter_child.localName == 'href':
-                    if not filter_child.firstChild:
-                        continue
-                    uri = filter_child.firstChild.data
-                    caluri = uri.split('/')
-                    if len(caluri):
-                        caluri = caluri[-2]
-                        if caluri not in names : names.append(caluri)
-                else:
-                    _log.debug("Unknonwn multiget element: %s", filter_child.localName)
-            res = [('name','in',names)]
-            return res
+            # this is not the place to process, as it wouldn't support multi-level
+            # hrefs. So, the code is moved to document_webdav/dav_fs.py
+            pass
         else:
             _log.debug("Unknown element in REPORT: %s", filters.localName)
         return res
@@ -289,22 +284,31 @@ class node_calendar(nodes.node_class):
         ctx = self.context.context.copy()
         ctx.update(self.dctx)
         where = []
+        bc_obj = dirobj.pool.get('basic.calendar')
+
         if name:
             if name.endswith('.ics'):
                 name = name[:-4]
             try:
-                where.append(('id','=',int(name)))
+                if name.isdigit():
+                    where.append(('id','=',int(name)))
+                else:
+                    bca_obj = dirobj.pool.get('basic.calendar.alias')
+                    bc_alias = bca_obj.search(cr, uid, 
+                        [('cal_line_id.calendar_id', '=', self.calendar_id),
+                         ('name', '=', name)] )
+                    if not bc_alias:
+                        return []
+                    bc_val = bca_obj.read(cr, uid, bc_alias, ['res_id',])
+                    where.append(('id', '=', bc_val[0]['res_id']))
             except ValueError:
                 # if somebody requests any other name than the ones we
                 # generate (non-numeric), it just won't exist
-                # FIXME: however, this confuses Evolution (at least), which
-                # thinks the .ics node hadn't been saved.
                 return []
 
         if not domain:
             domain = []
 
-        bc_obj = dirobj.pool.get('basic.calendar')
         # we /could/ be supplying an invalid calendar id to bc_obj, it has to check
         res = bc_obj.get_calendar_objects(cr, uid, [self.calendar_id], self, domain=where, context=ctx)
         return res
@@ -328,6 +332,21 @@ class node_calendar(nodes.node_class):
             assert isinstance(res[0], (int, long))
             fnodes = fil_obj.get_calendar_objects(cr, uid, [self.calendar_id], self,
                     domain=[('id','=',res[0])], context=ctx)
+            if self.context.get('DAV-client','') in ('iPhone', 'iCalendar',):
+                # For those buggy clients, register the alias
+                bca_obj = fil_obj.pool.get('basic.calendar.alias')
+                ourcal = fil_obj.browse(cr, uid, self.calendar_id)
+                line_id = None
+                for line in ourcal.line_ids:
+                    if line.name == ourcal.type:
+                        line_id = line.id
+                        break
+                assert line_id, "Calendar #%d must have at least one %s line" % \
+                                    (ourcal.id, ourcal.type)
+                if path.endswith('.ics'):
+                    path = path[:-4]
+                bca_obj.create(cr, uid, { 'cal_line_id': line_id, 
+                                    'res_id': res[0], 'name': path}, context=ctx)
             return fnodes[0]
         # If we reach this line, it means that we couldn't import any useful
         # (and matching type vs. our node kind) data from the iCal content.
@@ -350,11 +369,19 @@ class node_calendar(nodes.node_class):
         return False
 
     def _get_caldav_calendar_data(self, cr):
+        if self.context.get('DAV-client', '') in ('iPhone', 'iCalendar'):
+            # Never return collective data to iClients, they get confused
+            # because they do propfind on the calendar node with Depth=1
+            # and only expect the childrens' data
+            return None
         res = []
         for child in self.children(cr):
             res.append(child._get_caldav_calendar_data(cr))
         return res
 
+    def open_data(self, cr, mode):
+        return nodefd_static(self, cr, mode)
+
     def _get_caldav_calendar_description(self, cr):
         uid = self.context.uid
         calendar_obj = self.context._dirobj.pool.get('basic.calendar')
@@ -363,7 +390,7 @@ class node_calendar(nodes.node_class):
         try:
             calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
             return calendar.description or calendar.name
-        except Exception, e:
+        except Exception:
             return None
 
     def _get_dav_supported_report_set(self, cr):
@@ -422,7 +449,7 @@ class res_node_calendar(nodes.node_class):
         self.calendar_id = hasattr(parent, 'calendar_id') and parent.calendar_id or False
         if res_obj:
             if not self.calendar_id: self.calendar_id = res_obj.id
-            pr = res_obj.perm_read()[0]
+            pr = res_obj.perm_read(context=context, details=False)[0]
             self.create_date = pr.get('create_date')
             self.write_date = pr.get('write_date') or pr.get('create_date')
             self.displayname = res_obj.name
@@ -432,14 +459,10 @@ class res_node_calendar(nodes.node_class):
         self.model = res_model
         self.res_id = res_id
 
-    def open(self, cr, mode=False):
-        if self.type in ('collection','database'):
-            return False
-        s = StringIO.StringIO(self.get_data(cr))
-        s.name = self
-        return s
+    def open_data(self, cr, mode):
+        return nodefd_static(self, cr, mode)
 
-    def get_data(self, cr, fil_obj = None):
+    def get_data(self, cr, fil_obj=None):
         uid = self.context.uid
         calendar_obj = self.context._dirobj.pool.get('basic.calendar')
         context = self.context.context.copy()
@@ -471,6 +494,17 @@ class res_node_calendar(nodes.node_class):
             res = '%d' % (self.calendar_id)
         return res
 
+    def _get_wtag(self, cr):
+        uid = self.context.uid
+        context = self.context.context
+        if self.model and self.res_id:
+            mod_obj = self.context._dirobj.pool.get(self.model)
+            pr = mod_obj.perm_read(cr, uid, [self.res_id], context=context, details=False)[0]
+            self.write_date = pr.get('write_date') or pr.get('create_date')
+        
+        # Super will use self.write_date, so we should be fine.
+        return super(res_node_calendar, self)._get_wtag(cr)
+
     def rm(self, cr):
         uid = self.context.uid
         res = False