ソースを参照

correction of some bugs with moving objects and first revision of readme

Nonolost 8 年 前
コミット
388d9e07b4
共有3 個のファイルを変更した87 個の追加27 個の削除を含む
  1. 49 0
      tracim/tracim/lib/webdav/README.txt
  2. 6 1
      tracim/tracim/lib/webdav/sql_dav_provider.py
  3. 32 26
      tracim/tracim/lib/webdav/sql_resources.py

+ 49 - 0
tracim/tracim/lib/webdav/README.txt ファイルの表示

1
+## What is webdav ?
2
+
3
+Webdav's a extension of the HTTP protocol that introduces new requests (MKCOL, PROPFIND...) to ease the
4
+management of files on a distant server. More information can be found [here](https://tools.ietf.org/html/rfc4918).
5
+
6
+This project is based on the project [WSGIDav](https://github.com/mar10/wsgidav), which is an implementation of webdav in python that
7
+provides all basic needs to install a webdav on your server. This library intends to adapt WSGIDav implementation
8
+with the database based file management of Tracim, allowing users to access and modify files through their
9
+Window's file system.
10
+
11
+## Behavior to know about Windows' client and Webdav
12
+
13
+There are behaviors you may observe while using the windows' client for webdav which differ from other clients.
14
+
15
+* Window's will send twice each request. The first one as Anonymous, which will get a 401 Not Authorized, and then
16
+the second authentified which will proceed normally. This is the correct behavior that you have to observe for every webdav's client.
17
+In fact when sending
18
+The thing is that you'll observe only one request for clients like Debian's default filesystem because they cache the first response
19
+they got when sending an Anonymous request and they know that they have to send an authentication, thus they don't waste time sending
20
+twice the request.
21
+
22
+* When uploading new documents, windows will call twice put if the files does not exist. The first one with a length of 0 so that the resources
23
+can be locked before sending the whole file.
24
+
25
+* To display names, Windows won't use the displayName property but the object's path. Thus even if /a/b/c can link to a file named 'readme.txt' with
26
+   other webdav's client, you'll need to have a path named '/a/b/readme.txt' with Windows' client.
27
+
28
+## Known issues
29
+
30
+As for now, there's still some flaws or unexpected behaviors in the webdav implementation when using Windows' client.
31
+Though we could - and may - use github's issues to report them, we'll first write them down here to not pollute the
32
+original reports on tracim's _normal use_.
33
+
34
+* When moving files or folders from webdav to webdav, windows will warn you that this action may harm your computer. Though it won't say anything
35
+when moving files from your computer to webdav or vice-versa.
36
+
37
+* When deleting folders, Windows will go through all sub-folders and files recursively and request to delete them itself before going back to the main
38
+target. In our case it means it'll delete all sub-contents in database when we only want the parent to be in _deleted state_.
39
+Plus as a folder is _never empty_ (always contains .deleted and .archived) it won't even delete the folder because it'll first check if the target
40
+isn't empty before sending the final delete request.
41
+
42
+* Lock/unlock system is currently broken, thus it's not possible to work with office as it'll lock both the document and its temporary files and
43
+will be unable to unlock afterward, making it impossible to update them and making windows make a lot of unwanted request because the first failed.
44
+**Imma gonna correct it asap**.
45
+
46
+## Improving performances
47
+
48
+All request aren't still optimal and may take longer than what we want or expect. Here will be some tracks that will ease
49
+code refactoring to improve performances.

+ 6 - 1
tracim/tracim/lib/webdav/sql_dav_provider.py ファイルの表示

49
         """
49
         """
50
         Called by wsgidav whenever a request is called to get the _DAVResource corresponding to the path
50
         Called by wsgidav whenever a request is called to get the _DAVResource corresponding to the path
51
         """
51
         """
52
+        if not self.exists(path, environ):
53
+            return None
54
+
52
         path = normpath(path)
55
         path = normpath(path)
53
         root_path = environ['http_authenticator.realm']
56
         root_path = environ['http_authenticator.realm']
54
 
57
 
63
         # If the request path is in the form root/name, then we return a Workspace resource
66
         # If the request path is in the form root/name, then we return a Workspace resource
64
         parent_path = dirname(path)
67
         parent_path = dirname(path)
65
         if parent_path == root_path:
68
         if parent_path == root_path:
69
+            if not workspace:
70
+                return None
66
             return sql_resources.Workspace(path, environ, workspace)
71
             return sql_resources.Workspace(path, environ, workspace)
67
 
72
 
68
         # And now we'll work on the path to establish which type or resource is requested
73
         # And now we'll work on the path to establish which type or resource is requested
151
 
156
 
152
         workspace = self.get_workspace_from_path(path, WorkspaceApi(user))
157
         workspace = self.get_workspace_from_path(path, WorkspaceApi(user))
153
 
158
 
154
-        if parent_path == root_path:
159
+        if parent_path == root_path or workspace is None:
155
             return workspace is not None
160
             return workspace is not None
156
 
161
 
157
         content_api = ContentApi(user, show_archived=True, show_deleted=True)
162
         content_api = ContentApi(user, show_archived=True, show_deleted=True)

+ 32 - 26
tracim/tracim/lib/webdav/sql_resources.py ファイルの表示

199
         return self.workspace.label
199
         return self.workspace.label
200
 
200
 
201
     def getLastModified(self) -> float:
201
     def getLastModified(self) -> float:
202
+        print("hm....", self.path)
202
         return mktime(self.workspace.updated.timetuple())
203
         return mktime(self.workspace.updated.timetuple())
203
 
204
 
204
     def getMemberNames(self) -> [str]:
205
     def getMemberNames(self) -> [str]:
579
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
580
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
580
         
581
         
581
         for content in children:
582
         for content in children:
582
-            members.append(HistoryFileFolder(
583
-                path='%s/%s' % (self.path, content.get_label()),
584
-                environ=self.environ,
585
-                content=content))
583
+            if content.is_archived == self._is_archived and content.is_deleted == self._is_deleted:
584
+                members.append(HistoryFileFolder(
585
+                    path='%s/%s' % (self.path, content.get_label()),
586
+                    environ=self.environ,
587
+                    content=content))
586
 
588
 
587
         return members
589
         return members
588
 
590
 
647
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
649
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
648
 
650
 
649
         for content in children:
651
         for content in children:
650
-            content_path = '%s/%s' % (self.path, self.provider.transform_to_display(content.get_label()))
652
+            if content.is_deleted:
653
+                content_path = '%s/%s' % (self.path, self.provider.transform_to_display(content.get_label()))
651
 
654
 
652
-            if content.type == ContentType.Folder:
653
-                members.append(Folder(content_path, self.environ, self.workspace, content))
654
-            elif content.type == ContentType.File:
655
-                self._file_count += 1
656
-                members.append(File(content_path, self.environ, content))
657
-            else:
658
-                self._file_count += 1
659
-                members.append(OtherFile(content_path, self.environ, content))
655
+                if content.type == ContentType.Folder:
656
+                    members.append(Folder(content_path, self.environ, self.workspace, content))
657
+                elif content.type == ContentType.File:
658
+                    self._file_count += 1
659
+                    members.append(File(content_path, self.environ, content))
660
+                else:
661
+                    self._file_count += 1
662
+                    members.append(OtherFile(content_path, self.environ, content))
660
 
663
 
661
         if self._file_count > 0 and self.provider.show_history():
664
         if self._file_count > 0 and self.provider.show_history():
662
             members.append(
665
             members.append(
726
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
729
             children = self.content_api.get_all(None, ContentType.Any, self.workspace)
727
 
730
 
728
         for content in children:
731
         for content in children:
729
-            content_path = '%s/%s' % (self.path, self.provider.transform_to_display(content.get_label()))
732
+            if content.is_archived:
733
+                content_path = '%s/%s' % (self.path, self.provider.transform_to_display(content.get_label()))
730
 
734
 
731
-            if content.type == ContentType.Folder:
732
-                members.append(Folder(content_path, self.environ, self.workspace, content))
733
-            elif content.type == ContentType.File:
734
-                self._file_count += 1
735
-                members.append(File(content_path, self.environ, content))
736
-            else:
737
-                self._file_count += 1
738
-                members.append(OtherFile(content_path, self.environ, content))
735
+                if content.type == ContentType.Folder:
736
+                    members.append(Folder(content_path, self.environ, self.workspace, content))
737
+                elif content.type == ContentType.File:
738
+                    self._file_count += 1
739
+                    members.append(File(content_path, self.environ, content))
740
+                else:
741
+                    self._file_count += 1
742
+                    members.append(OtherFile(content_path, self.environ, content))
739
 
743
 
740
         if self._file_count > 0 and self.provider.show_history():
744
         if self._file_count > 0 and self.provider.show_history():
741
             members.append(
745
             members.append(
932
             raise DAVError(HTTP_FORBIDDEN)
936
             raise DAVError(HTTP_FORBIDDEN)
933
 
937
 
934
     def move_file(self, destpath):
938
     def move_file(self, destpath):
935
-        parent = self.provider.get_parent_from_path(
939
+
940
+        workspace = self.provider.get_workspace_from_path(
936
             normpath(destpath),
941
             normpath(destpath),
937
-            self.content_api,
938
             WorkspaceApi(self.user)
942
             WorkspaceApi(self.user)
939
         )
943
         )
940
 
944
 
941
-        workspace = self.provider.get_workspace_from_path(
945
+        parent = self.provider.get_parent_from_path(
942
             normpath(destpath),
946
             normpath(destpath),
943
-            WorkspaceApi(self.user)
947
+            self.content_api,
948
+            workspace
944
         )
949
         )
945
 
950
 
951
+
946
         with new_revision(self.content):
952
         with new_revision(self.content):
947
             if basename(destpath) != self.getDisplayName():
953
             if basename(destpath) != self.getDisplayName():
948
                 self.content_api.update_content(self.content, re.sub('\.[^\.]+$', '', self.provider.transform_to_bdd(basename(destpath))))
954
                 self.content_api.update_content(self.content, re.sub('\.[^\.]+$', '', self.provider.transform_to_bdd(basename(destpath))))