~openerp-commiter/openobject-addons/extra-6.0

« back to all changes in this revision

Viewing changes to document_webdav_old/webdav/dav_fs.py

  • Committer: Fabien Pinckaers
  • Date: 2008-12-12 09:09:57 UTC
  • Revision ID: fp@tinyerp.com-20081212090957-cson0n0jove7dt7i
document_webdav

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import pooler
 
2
 
 
3
import base64
 
4
import sys
 
5
import os
 
6
import time
 
7
from string import joinfields, split, lower
 
8
 
 
9
from DAV import AuthServer
 
10
from service import security
 
11
import dav_auth
 
12
 
 
13
import netsvc
 
14
import urlparse
 
15
from content_index import content_index
 
16
 
 
17
from DAV.constants import COLLECTION, OBJECT
 
18
from DAV.errors import *
 
19
from DAV.iface import *
 
20
import urllib
 
21
 
 
22
from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree
 
23
 
 
24
from cache import memoize
 
25
 
 
26
CACHE_SIZE=20000
 
27
 
 
28
class tinyerp_handler(dav_interface):
 
29
        """
 
30
        This class models a Tiny ERP interface for the DAV server
 
31
        """
 
32
        def __init__(self,  host,port,  verbose=False):
 
33
                self.db_name = False
 
34
                self.directory_id=False
 
35
                self.host=host
 
36
                self.port=port
 
37
                self.baseuri = 'http://%s:%s/' % (self.host, self.port)
 
38
                self.db_name_list=[]
 
39
#
 
40
#
 
41
#       def get_db(self,uri):
 
42
#               names=self.uri2local(uri).split('/')
 
43
#               self.db_name=False
 
44
#               if len(names) > 1:
 
45
#                       self.db_name=self.uri2local(uri).split('/')[1]
 
46
#                       if self.db_name=='':
 
47
#                               raise Exception,'Plese specify Database name in folder'
 
48
#               return self.db_name
 
49
#
 
50
 
 
51
        @memoize(500)
 
52
        def is_db(self, uri):
 
53
                reluri = self.uri2local(uri)
 
54
                return not len(reluri.split('/'))>1
 
55
 
 
56
        @memoize(4)
 
57
        def db_list(self):
 
58
                print '*'*90
 
59
                s = netsvc.LocalService('db')
 
60
                result = s.list()
 
61
                self.db_name_list=[]
 
62
                for db_name in result:
 
63
                        db = pooler.get_db_only(db_name)
 
64
                        cr = db.cursor()
 
65
                        cr.execute("select id from ir_module_module where name = 'document' and state='installed' ")
 
66
                        res=cr.fetchone()
 
67
                        if res and len(res):
 
68
                                self.db_name_list.append(db_name)
 
69
                        cr.close()
 
70
                return self.db_name_list
 
71
 
 
72
        def get_childs(self,uri):
 
73
                """ return the child objects as self.baseuris for the given URI """
 
74
                if self.is_db(uri):
 
75
                        s = netsvc.LocalService('db')
 
76
                        return map(lambda x: urlparse.urljoin(self.baseuri, x), self.db_list())
 
77
                result = []
 
78
                if uri[-1]=='/':uri=uri[:-1]
 
79
                cr, uid, pool, uri2 = self.get_cr(uri)
 
80
                node = self.uri2object(cr,uid,pool, uri2[:])
 
81
                for d in node.children():
 
82
                        result.append( urlparse.urljoin(self.baseuri, d.path) )
 
83
                return result
 
84
 
 
85
        def uri2local(self, uri):
 
86
                uparts=urlparse.urlparse(uri)
 
87
                reluri=uparts[2]
 
88
                if reluri and reluri[-1]=="/":
 
89
                        reluri=reluri[:-1]
 
90
                return reluri
 
91
 
 
92
        #
 
93
        # pos: -1 to get the parent of the uri
 
94
        #
 
95
        def get_cr(self, uri):
 
96
                reluri = self.uri2local(uri)
 
97
                dbname = reluri.split('/')[1]
 
98
                uid = security.login(dbname, dav_auth.auth['user'], dav_auth.auth['pwd'])
 
99
                db,pool = pooler.get_db_and_pool(dbname)
 
100
                cr = db.cursor()
 
101
                uri2 = reluri.split('/')[1:]
 
102
                return cr, uid, pool, uri2
 
103
 
 
104
        def uri2object(self, cr,uid, pool,uri):
 
105
                return pool.get('document.directory').get_object(cr, uid, uri)
 
106
 
 
107
        def get_data(self,uri):
 
108
                if self.is_db(uri):
 
109
                        raise DAV_Error, 409
 
110
                if uri[-1]=='/':uri=uri[:-1]
 
111
                cr, uid, pool, uri2 = self.get_cr(uri)
 
112
                node = self.uri2object(cr,uid,pool, uri2)
 
113
                if not node:
 
114
                        raise DAV_NotFound
 
115
                if node.type=='file':
 
116
                        datas=False
 
117
                        if node.object.datas:
 
118
                                datas=node.object.datas
 
119
                        elif node.object.link:
 
120
                                import urllib
 
121
                                datas=base64.encodestring(urllib.urlopen(node.object.link).read())
 
122
                        return base64.decodestring(datas or '')
 
123
                elif node.type=='content':
 
124
                        report = pool.get('ir.actions.report.xml').browse(cr, uid, node.content['report_id']['id'])
 
125
                        srv = netsvc.LocalService('report.'+report.report_name)
 
126
                        pdf,pdftype = srv.create(cr, uid, [node.object.id], {}, {})
 
127
                        return pdf
 
128
                else:
 
129
                        raise DAV_Forbidden
 
130
 
 
131
        @memoize(CACHE_SIZE)
 
132
        def _get_dav_resourcetype(self,uri):
 
133
                """ return type of object """
 
134
                print 'RT', uri
 
135
                if uri[-1]=='/':uri=uri[:-1]
 
136
                if self.is_db(uri):
 
137
                        return COLLECTION
 
138
                cr, uid, pool, uri2 = self.get_cr(uri)
 
139
                node = self.uri2object(cr,uid,pool, uri2)
 
140
                cr.close()
 
141
                if node.type in ('collection','database'):
 
142
                        return COLLECTION
 
143
                return OBJECT
 
144
 
 
145
        def _get_dav_displayname(self,uri):
 
146
                raise DAV_Secret
 
147
 
 
148
        @memoize(CACHE_SIZE)
 
149
        def _get_dav_getcontentlength(self,uri):
 
150
                """ return the content length of an object """
 
151
                print 'Get DAV CL', uri
 
152
                if uri[-1]=='/':uri=uri[:-1]
 
153
                if self.is_db(uri):
 
154
                        return '0'
 
155
                result = 0
 
156
                cr, uid, pool, uri2 = self.get_cr(uri)
 
157
                node = self.uri2object(cr, uid, pool, uri2)
 
158
                if node.type=='file':
 
159
                        result = node.object.file_size or 0
 
160
                cr.close()
 
161
                return str(result)
 
162
 
 
163
        @memoize(CACHE_SIZE)
 
164
        def get_lastmodified(self,uri):
 
165
                """ return the last modified date of the object """
 
166
                print 'Get DAV Mod', uri
 
167
                if uri[-1]=='/':uri=uri[:-1]
 
168
                today = time.time()
 
169
                #return today
 
170
                if self.is_db(uri):
 
171
                        return today
 
172
                cr, uid, pool, uri2 = self.get_cr(uri)
 
173
                node = self.uri2object(cr,uid,pool, uri2)
 
174
                if node.type=='file':
 
175
                        dt = node.object.write_date or node.object.create_date
 
176
                        result = int(time.mktime(time.strptime(dt,'%Y-%m-%d %H:%M:%S')))
 
177
                else:
 
178
                        result = today
 
179
                cr.close()
 
180
                return result
 
181
 
 
182
        @memoize(CACHE_SIZE)
 
183
        def get_creationdate(self,uri):
 
184
                """ return the last modified date of the object """
 
185
                print 'Get DAV Cre', uri
 
186
 
 
187
                if self.is_db(uri):
 
188
                        raise DAV_Error, 409
 
189
                if uri[-1]=='/':uri=uri[:-1]
 
190
                cr, uid, pool, uri2 = self.get_cr(uri)
 
191
                node = self.uri2object(cr,uid,pool, uri2)
 
192
                if node.type=='file':
 
193
                        result = node.object.write_date or node.object.create_date
 
194
                else:
 
195
                        result = time.strftime('%Y-%m-%d %H:%M:%S')
 
196
                cr.close()
 
197
                return time.mktime(time.strptime(result,'%Y-%m-%d %H:%M:%S'))
 
198
 
 
199
        @memoize(CACHE_SIZE)
 
200
        def _get_dav_getcontenttype(self,uri):
 
201
                print 'Get DAV CT', uri
 
202
                if uri[-1]=='/':uri=uri[:-1]
 
203
                if self.is_db(uri):
 
204
                        return 'httpd/unix-directory'
 
205
                cr, uid, pool, uri2 = self.get_cr(uri)
 
206
                node = self.uri2object(cr,uid,pool, uri2)
 
207
                result = 'application/octet-stream'
 
208
                if node.type=='collection':
 
209
                        return 'httpd/unix-directory'
 
210
                cr.close()
 
211
                return result
 
212
                #raise DAV_NotFound, 'Could not find %s' % path
 
213
 
 
214
        def mkcol(self,uri):
 
215
                """ create a new collection """
 
216
                print 'MKCOL', uri
 
217
                if uri[-1]=='/':uri=uri[:-1]
 
218
                if self.is_db(uri):
 
219
                        raise DAV_Error, 409
 
220
                parent='/'.join(uri.split('/')[:-1])
 
221
                if not parent.startswith(self.baseuri):
 
222
                        parent=self.baseuri + ''.join(parent[1:])
 
223
                if not uri.startswith(self.baseuri):
 
224
                        uri=self.baseuri + ''.join(uri[1:])
 
225
 
 
226
 
 
227
                cr, uid, pool, uri2 = self.get_cr(uri)
 
228
                node = self.uri2object(cr,uid,pool, uri2[:-1])
 
229
                object2=node and node.object2 or False
 
230
                object=node and node.object or False
 
231
 
 
232
                objname = uri2[-1]
 
233
                if not object:
 
234
                        pool.get('document.directory').create(cr, uid, {
 
235
                                'name': objname,
 
236
                                'parent_id': False,
 
237
                                'ressource_type_id': False,
 
238
                                'ressource_id': False
 
239
                        })
 
240
                else:
 
241
                        pool.get('document.directory').create(cr, uid, {
 
242
                                'name': objname,
 
243
                                'parent_id': object.id,
 
244
                                'ressource_type_id': object.ressource_type_id.id,
 
245
                                'ressource_id': object2 and object2.id or False
 
246
                        })
 
247
 
 
248
                cr.commit()
 
249
                cr.close()
 
250
                return 201
 
251
 
 
252
        def put(self,uri,data,content_type=None):
 
253
                """ put the object into the filesystem """
 
254
                print 'Putting', uri, len(data), content_type
 
255
                if self.is_db(uri):
 
256
                        raise DAV_Forbidden
 
257
                parent='/'.join(uri.split('/')[:-1])
 
258
                cr, uid, pool, uri2 = self.get_cr(uri)
 
259
                print 'Looking Node'
 
260
                try:
 
261
                        node = self.uri2object(cr,uid,pool, uri2[:])
 
262
                except:
 
263
                        node = False
 
264
                print 'NODE FOUND', node
 
265
                fobj = pool.get('ir.attachment')
 
266
                objname = uri2[-1]
 
267
                ext = objname.find('.') >0 and objname.split('.')[1] or False
 
268
                if node and node.type=='file':
 
269
                        print '*** FILE', node.object
 
270
                        val = {
 
271
                                'file_size': len(data),
 
272
                                'datas': base64.encodestring(data),
 
273
                        }
 
274
                        cid = fobj.write(cr, uid, [node.object.id], val)
 
275
                        cr.commit()
 
276
                elif not node:
 
277
                        print '*** CREATE', 'not node'
 
278
                        node = self.uri2object(cr,uid,pool, uri2[:-1])
 
279
                        object2=node and node.object2 or False
 
280
                        object=node and node.object or False
 
281
                        val = {
 
282
                                'name': objname,
 
283
                                'datas_fname': objname,
 
284
                                'file_size': len(data),
 
285
                                'datas': base64.encodestring(data),
 
286
                                'file_type': ext,
 
287
                                'parent_id': object and object.id or False,
 
288
                        }
 
289
                        partner = False
 
290
                        if object2.partner_id and object2.partner_id.id:
 
291
                                partner = object2.partner_id.id
 
292
                        if object2._name == 'res.partner':
 
293
                                partner = object2.id
 
294
                        if object2:
 
295
                                val.update( {
 
296
                                        'res_model': object2._name,
 
297
                                        'partner_id': partner,
 
298
                                        'res_id': object2.id
 
299
                                })
 
300
                        cid = fobj.create(cr, uid, val)
 
301
                        cr.commit()
 
302
 
 
303
                        # TODO: Test Permissions
 
304
                        if False:
 
305
                                raise DAV_Forbidden
 
306
                        cr.close()
 
307
                        return 201
 
308
                else:
 
309
                        print '*** FORB'
 
310
                        raise DAV_Forbidden
 
311
 
 
312
        def rmcol(self,uri):
 
313
                """ delete a collection """
 
314
                if uri[-1]=='/':uri=uri[:-1]
 
315
                if self.is_db(uri):
 
316
                        raise DAV_Error, 409
 
317
 
 
318
                cr, uid, pool, uri2 = self.get_cr(uri)
 
319
                node = self.uri2object(cr,uid,pool, uri2)
 
320
                object2=node and node.object2 or False
 
321
                object=node and node.object or False
 
322
                if object._table_name=='document.directory':
 
323
                        if object.child_ids:
 
324
                                raise DAV_Forbidden # forbidden
 
325
                        if object.file_ids:
 
326
                                raise DAV_Forbidden # forbidden
 
327
                        res = pool.get('document.directory').unlink(cr, uid, [object.id])
 
328
 
 
329
                cr.commit()
 
330
                cr.close()
 
331
                return 204
 
332
 
 
333
        def rm(self,uri):
 
334
                if uri[-1]=='/':uri=uri[:-1]
 
335
                if self.is_db(uri):
 
336
                        raise DAV_Error, 409
 
337
 
 
338
                object=False
 
339
                cr, uid, pool, uri2 = self.get_cr(uri)
 
340
                node = self.uri2object(cr,uid,pool, uri2)
 
341
                object2=node and node.object2 or False
 
342
                object=node and node.object or False
 
343
                if not object:
 
344
                        raise DAV_NotFound, 404
 
345
 
 
346
                print ' rm',object._table_name,uri
 
347
                if object._table_name=='ir.attachment':
 
348
                        res = pool.get('ir.attachment').unlink(cr, uid, [object.id])
 
349
                else:
 
350
                        raise DAV_Forbidden # forbidden
 
351
                parent='/'.join(uri.split('/')[:-1])
 
352
                cr.commit()
 
353
                cr.close()
 
354
                return 204
 
355
 
 
356
        ### DELETE handlers (examples)
 
357
        ### (we use the predefined methods in davcmd instead of doing
 
358
        ### a rm directly
 
359
        ###
 
360
 
 
361
        def delone(self,uri):
 
362
                """ delete a single resource
 
363
 
 
364
                You have to return a result dict of the form
 
365
                uri:error_code
 
366
                or None if everything's ok
 
367
 
 
368
                """
 
369
                if uri[-1]=='/':uri=uri[:-1]
 
370
                res=delone(self,uri)
 
371
                parent='/'.join(uri.split('/')[:-1])
 
372
                return res
 
373
 
 
374
        def deltree(self,uri):
 
375
                """ delete a collection
 
376
 
 
377
                You have to return a result dict of the form
 
378
                uri:error_code
 
379
                or None if everything's ok
 
380
                """
 
381
                if uri[-1]=='/':uri=uri[:-1]
 
382
                res=deltree(self,uri)
 
383
                parent='/'.join(uri.split('/')[:-1])
 
384
                return res
 
385
 
 
386
 
 
387
        ###
 
388
        ### MOVE handlers (examples)
 
389
        ###
 
390
 
 
391
        def moveone(self,src,dst,overwrite):
 
392
                """ move one resource with Depth=0
 
393
 
 
394
                an alternative implementation would be
 
395
 
 
396
                result_code=201
 
397
                if overwrite:
 
398
                        result_code=204
 
399
                        r=os.system("rm -f '%s'" %dst)
 
400
                        if r: return 412
 
401
                r=os.system("mv '%s' '%s'" %(src,dst))
 
402
                if r: return 412
 
403
                return result_code
 
404
 
 
405
                (untested!). This would not use the davcmd functions
 
406
                and thus can only detect errors directly on the root node.
 
407
                """
 
408
                res=moveone(self,src,dst,overwrite)
 
409
                return res
 
410
 
 
411
        def movetree(self,src,dst,overwrite):
 
412
                """ move a collection with Depth=infinity
 
413
 
 
414
                an alternative implementation would be
 
415
 
 
416
                result_code=201
 
417
                if overwrite:
 
418
                        result_code=204
 
419
                        r=os.system("rm -rf '%s'" %dst)
 
420
                        if r: return 412
 
421
                r=os.system("mv '%s' '%s'" %(src,dst))
 
422
                if r: return 412
 
423
                return result_code
 
424
 
 
425
                (untested!). This would not use the davcmd functions
 
426
                and thus can only detect errors directly on the root node"""
 
427
 
 
428
                res=movetree(self,src,dst,overwrite)
 
429
                return res
 
430
 
 
431
        ###
 
432
        ### COPY handlers
 
433
        ###
 
434
 
 
435
        def copyone(self,src,dst,overwrite):
 
436
                """ copy one resource with Depth=0
 
437
 
 
438
                an alternative implementation would be
 
439
 
 
440
                result_code=201
 
441
                if overwrite:
 
442
                        result_code=204
 
443
                        r=os.system("rm -f '%s'" %dst)
 
444
                        if r: return 412
 
445
                r=os.system("cp '%s' '%s'" %(src,dst))
 
446
                if r: return 412
 
447
                return result_code
 
448
 
 
449
                (untested!). This would not use the davcmd functions
 
450
                and thus can only detect errors directly on the root node.
 
451
                """
 
452
                res=copyone(self,src,dst,overwrite)
 
453
                return res
 
454
 
 
455
        def copytree(self,src,dst,overwrite):
 
456
                """ copy a collection with Depth=infinity
 
457
 
 
458
                an alternative implementation would be
 
459
 
 
460
                result_code=201
 
461
                if overwrite:
 
462
                        result_code=204
 
463
                        r=os.system("rm -rf '%s'" %dst)
 
464
                        if r: return 412
 
465
                r=os.system("cp -r '%s' '%s'" %(src,dst))
 
466
                if r: return 412
 
467
                return result_code
 
468
 
 
469
                (untested!). This would not use the davcmd functions
 
470
                and thus can only detect errors directly on the root node"""
 
471
                res=copytree(self,src,dst,overwrite)
 
472
                return res
 
473
 
 
474
        ###
 
475
        ### copy methods.
 
476
        ### This methods actually copy something. low-level
 
477
        ### They are called by the davcmd utility functions
 
478
        ### copytree and copyone (not the above!)
 
479
        ### Look in davcmd.py for further details.
 
480
        ###
 
481
 
 
482
        def copy(self,src,dst):
 
483
                src=urllib.unquote(src)
 
484
                dst=urllib.unquote(dst)
 
485
                ct = self._get_dav_getcontenttype(src)
 
486
                data = self.get_data(src)
 
487
                self.put(dst,data,ct)
 
488
                return 201
 
489
 
 
490
        def copycol(self,src,dst):
 
491
                """ copy a collection.
 
492
 
 
493
                As this is not recursive (the davserver recurses itself)
 
494
                we will only create a new directory here. For some more
 
495
                advanced systems we might also have to copy properties from
 
496
                the source to the destination.
 
497
                """
 
498
                print " copy a collection."
 
499
                return self.mkcol(dst)
 
500
 
 
501
 
 
502
        def exists(self,uri):
 
503
                """ test if a resource exists """
 
504
                if self.is_db(uri):
 
505
                        return True
 
506
                result = False
 
507
                cr, uid, pool, uri2 = self.get_cr(uri)
 
508
                try:
 
509
                        node = self.uri2object(cr,uid,pool, uri2)
 
510
                        if node:
 
511
                                result = True
 
512
                except:
 
513
                        pass
 
514
                cr.close()
 
515
                print 'Get Exists', uri, result
 
516
                return result
 
517
 
 
518
        @memoize(CACHE_SIZE)
 
519
        def is_collection(self,uri):
 
520
                """ test if the given uri is a collection """
 
521
                return self._get_dav_resourcetype(uri)==COLLECTION