5 use this for subclassing when writing your own interface
13 from string import lower
16 """ interface class for implementing DAV servers """
18 ### defined properties (modify this but let the DAV stuff there!)
19 ### the format is namespace: [list of properties]
21 PROPS={"DAV:" : ('creationdate',
35 # here we define which methods handle which namespace
36 # the first item is the namespace URI and the second one
38 # e.g. for DAV:getcontenttype we call dav_getcontenttype()
39 M_NS={"DAV:" : "_get_dav",
42 def get_propnames(self,uri):
43 """ return the property names allowed for the given URI
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.
53 def get_prop2(self,uri,ns,pname):
54 """ return the value of a property
56 if lower(ns)=="dav:": return self.get_dav(uri,pname)
60 def get_prop(self,uri,ns,propname):
61 """ return the value of a given property
63 uri -- uri of the object to get the property of
64 ns -- namespace of the property
65 pname -- name of the property
67 if self.M_NS.has_key(ns):
70 print "No namespace:",ns
72 mname=prefix+"_"+propname
73 if not hasattr(self,mname):
80 except AttributeError, e:
81 print 'Property %s not supported' % propname
86 ### DATA methods (for GET and PUT)
89 def get_data(self,uri):
90 """ return the content of an object
92 return data or raise an exception
97 def put(self,uri,data):
98 """ write an object to the repository
100 return a result code or raise an exception
106 ### Methods for DAV properties
109 def _get_dav_creationdate(self,uri):
110 """ return the creationdate of a resource """
111 d=self.get_creationdate(uri)
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)
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)
123 return time.asctime(d)
130 def get_creationdate(self,uri):
131 """ return the creationdate of the resource """
134 def get_lastmodified(self,uri):
135 """ return the last modification date of the resource """
143 ### methods for deleting a resource
146 """ delete a collection
148 This should not delete any children! This is automatically done
149 before by the DELETE class in DAV/delete.py
151 return a success code or raise an exception
157 """ delete a single resource
159 return a success code or raise an exception
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:
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
177 copyone for a single resource to copy
178 copytree for a tree to copy (collection)
179 (the same goes for move of course).
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.
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, ...}
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.
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.
207 The remaining question is if we should do the same for the DELETE method.
213 def moveone(self,src,dst,overwrite):
214 """ move one resource with Depth=0 """
215 return moveone(self,src,dst,overwrite)
217 def movetree(self,src,dst,overwrite):
218 """ move a collection with Depth=infinity """
219 return movetree(self,src,dst,overwrite)
223 def copyone(self,src,dst,overwrite):
224 """ copy one resource with Depth=0 """
225 return copyone(self,src,dst,overwrite)
227 def copytree(self,src,dst,overwrite):
228 """ copy a collection with Depth=infinity """
229 return copytree(self,src,dst,overwrite)
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
236 You don't need to bother about overwrite or not.
237 This has been done already.
239 return a success code or raise an exception if something fails
244 def copycol(self,src,dst):
245 """ copy a resource with depth==infinity
247 You don't need to bother about overwrite or not.
248 This has been done already.
250 return a success code or raise an exception if something fails
254 ### some utility functions you need to implement
256 def exists(self,uri):
257 """ return 1 or None depending on if a resource exists """
260 def is_collection(self,uri):
261 """ return 1 or None depending on if a resource is a collection """