8f6daa5eaa80afe06acc5263b96c146a1e100de1
[odoo/odoo.git] / addons / document_webdav / DAV / iface.py
1 """
2
3 basic interface class
4
5 use this for subclassing when writing your own interface
6 class.
7
8 """
9
10 from errors import *
11
12 import time
13 from string import lower
14
15 class dav_interface:
16     """ interface class for implementing DAV servers """
17
18     ### defined properties (modify this but let the DAV stuff there!)
19     ### the format is namespace: [list of properties]
20
21     PROPS={"DAV:" : ('creationdate', 
22                      'displayname', 
23                      'getcontentlanguage', 
24                      'getcontentlength', 
25                      'getcontenttype', 
26                      'getetag', 
27                      'getlastmodified', 
28                      'lockdiscovery', 
29                      'resourcetype', 
30                      'source', 
31                      'supportedlock'),
32            "NS2" : ("p1","p2")
33            }
34
35     # here we define which methods handle which namespace
36     # the first item is the namespace URI and the second one
37     # the method prefix
38     # e.g. for DAV:getcontenttype we call dav_getcontenttype()
39     M_NS={"DAV:" : "_get_dav",
40           "NS2"  : "ns2" }
41
42     def get_propnames(self,uri):
43         """ return the property names allowed for the given URI 
44
45         In this method we simply return the above defined properties
46         assuming that they are valid for any resource. 
47         You can override this in order to return a different set
48         of property names for each resource.
49         
50         """
51         return self.PROPS
52
53     def get_prop2(self,uri,ns,pname):
54         """ return the value of a property 
55         """
56         if lower(ns)=="dav:": return self.get_dav(uri,pname)
57
58         raise DAV_NotFound
59
60     def get_prop(self,uri,ns,propname):
61         """ return the value of a given property
62
63         uri        -- uri of the object to get the property of
64         ns        -- namespace of the property
65         pname        -- name of the property
66         """
67         if self.M_NS.has_key(ns):
68             prefix=self.M_NS[ns]
69         else:
70             print "No namespace:",ns
71             raise DAV_NotFound
72         mname=prefix+"_"+propname
73         if not hasattr(self,mname):
74             raise DAV_NotFound
75
76         try:
77             m=getattr(self,mname)
78             r=m(uri)
79             return r
80         except AttributeError, e:
81             print 'Property %s not supported' % propname
82             print "Exception:", e
83             raise DAV_NotFound
84
85     ###
86     ### DATA methods (for GET and PUT)
87     ###
88
89     def get_data(self,uri):
90         """ return the content of an object 
91
92         return data or raise an exception
93         
94         """
95         raise DAV_NotFound
96
97     def put(self,uri,data):
98         """ write an object to the repository 
99
100         return a result code or raise an exception
101         """
102
103         raise DAV_Forbidden
104
105     ###
106     ### Methods for DAV properties
107     ###
108
109     def _get_dav_creationdate(self,uri):
110         """ return the creationdate of a resource """
111         d=self.get_creationdate(uri)
112         # format it
113         if isinstance(d, int) or isinstance(d, float):
114                 d = time.localtimetime(d)
115         return time.strftime("%Y-%m-%dT%H:%M:%S%Z",d)
116
117     def _get_dav_getlastmodified(self,uri):
118         """ return the last modified date of a resource """
119         d=self.get_lastmodified(uri)
120         if isinstance(d, int) or isinstance(d, float):
121                 d = time.localtime(d)
122         # format it
123         return time.asctime(d)
124
125
126     ###
127     ### OVERRIDE THESE!
128     ###
129
130     def get_creationdate(self,uri):
131         """ return the creationdate of the resource """
132         return time.time()
133
134     def get_lastmodified(self,uri):
135         """ return the last modification date of the resource """
136         return time.time()
137
138     
139     ###
140     ### COPY MOVE DELETE
141     ###
142
143     ### methods for deleting a resource
144
145     def rmcol(self,uri):
146         """ delete a collection 
147
148         This should not delete any children! This is automatically done
149         before by the DELETE class in DAV/delete.py
150
151         return a success code or raise an exception
152         
153         """
154         raise DAV_NotFound
155
156     def rm(self,uri):
157         """ delete a single resource 
158
159         return a success code or raise an exception
160         
161         """
162         raise DAV_NotFound
163
164     """
165
166     COPY/MOVE HANDLER
167
168     These handler are called when a COPY or MOVE method is invoked by
169     a client. In the default implementation it works as follows:
170
171     - the davserver receives a COPY/MOVE method
172     - the davcopy or davmove module will be loaded and the corresponding
173       class will be initialized
174     - this class parses the query and decides which method of the interface class
175       to call:
176
177       copyone for a single resource to copy
178       copytree for a tree to copy (collection)
179       (the same goes for move of course).
180
181     - the interface class has now two options:
182         1. to handle the action directly (e.g. cp or mv on filesystems)
183         2. to let it handle via the copy/move methods in davcmd.
184
185     ad 1) The first approach can be used when we know that no error can 
186           happen inside a tree or when the action can exactly tell which
187           element made which error. We have to collect these and return
188           it in a dict of the form {uri: error_code, ...}
189
190     ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion
191           themselves and call for each resource the copy/move method of the
192           interface class. Thus method will then only act on a single resource.
193           (Thus a copycol on a normal unix filesystem actually only needs to do
194           an mkdir as the content will be copied by the davcmd.py function.
195           The davcmd.py method will also automatically collect all errors and
196           return the dictionary described above.
197           When you use 2) you also have to implement the copy() and copycol()
198           methods in your interface class. See the example for details.
199
200     To decide which approach is the best you have to decide if your application
201     is able to generate errors inside a tree. E.g. a function which completely
202     fails on a tree if one of the tree's childs fail is not what we need. Then
203     2) would be your way of doing it.
204     Actually usually 2) is the better solution and should only be replaced by
205     1) if you really need it.
206
207     The remaining question is if we should do the same for the DELETE method.
208
209     """
210
211     ### MOVE handlers
212
213     def moveone(self,src,dst,overwrite):
214         """ move one resource with Depth=0 """
215         return moveone(self,src,dst,overwrite)
216
217     def movetree(self,src,dst,overwrite):
218         """ move a collection with Depth=infinity """
219         return movetree(self,src,dst,overwrite)
220
221     ### COPY handlers
222
223     def copyone(self,src,dst,overwrite):
224         """ copy one resource with Depth=0 """
225         return copyone(self,src,dst,overwrite)
226
227     def copytree(self,src,dst,overwrite):
228         """ copy a collection with Depth=infinity """
229         return copytree(self,src,dst,overwrite)
230
231
232     ### low level copy methods (you only need these for method 2)
233     def copy(self,src,dst):
234         """ copy a resource with depth==0 
235
236         You don't need to bother about overwrite or not.
237         This has been done already.
238
239         return a success code or raise an exception if something fails
240         """
241         return 201
242
243
244     def copycol(self,src,dst):
245         """ copy a resource with depth==infinity 
246
247         You don't need to bother about overwrite or not.
248         This has been done already.
249
250         return a success code or raise an exception if something fails
251         """
252         return 201
253
254     ### some utility functions you need to implement
255
256     def exists(self,uri):
257         """ return 1 or None depending on if a resource exists """
258         return None # no
259
260     def is_collection(self,uri):
261         """ return 1 or None depending on if a resource is a collection """
262         return None # no
263