Преглед на файлове

Merge pull request #61 from tracim/fix/52_fix_sqlalchemy_issue_for_webdav

Damien Accorsi преди 7 години
родител
ревизия
20ba34967e
No account linked to committer's email
променени са 5 файла, в които са добавени 245 реда и са изтрити 111 реда
  1. 1 1
      tracim/lib/webdav/__init__.py
  2. 12 12
      tracim/lib/webdav/dav_provider.py
  3. 209 84
      tracim/lib/webdav/resources.py
  4. 14 1
      tracim/models/__init__.py
  5. 9 13
      tracim/tests/library/test_webdav.py

+ 1 - 1
tracim/lib/webdav/__init__.py Целия файл

@@ -75,9 +75,9 @@ class WebdavAppFactory(object):
75 75
             WsgiDavDirBrowser,
76 76
             TracimUserSession,
77 77
             HTTPAuthenticator,
78
-            TracimEnv,
79 78
             ErrorPrinter,
80 79
             TracimWsgiDavDebugFilter,
80
+            TracimEnv,
81 81
 
82 82
         ]
83 83
         config['provider_mapping'] = {

+ 12 - 12
tracim/lib/webdav/dav_provider.py Целия файл

@@ -68,19 +68,19 @@ class Provider(DAVProvider):
68 68
         path = normpath(path)
69 69
         root_path = environ['http_authenticator.realm']
70 70
 
71
-        # If the requested path is the root, then we return a Root resource
71
+        # If the requested path is the root, then we return a RootResource resource
72 72
         if path == root_path:
73
-            return resources.Root(path, environ, user=user, session=session)
73
+            return resources.RootResource(path, environ, user=user, session=session)
74 74
 
75 75
         workspace_api = WorkspaceApi(current_user=user, session=session)
76 76
         workspace = self.get_workspace_from_path(path, workspace_api)
77 77
 
78
-        # If the request path is in the form root/name, then we return a Workspace resource
78
+        # If the request path is in the form root/name, then we return a WorkspaceResource resource
79 79
         parent_path = dirname(path)
80 80
         if parent_path == root_path:
81 81
             if not workspace:
82 82
                 return None
83
-            return resources.Workspace(
83
+            return resources.WorkspaceResource(
84 84
                 path=path,
85 85
                 environ=environ,
86 86
                 workspace=workspace,
@@ -107,10 +107,10 @@ class Provider(DAVProvider):
107 107
 
108 108
         # Easy cases : path either end with /.deleted, /.archived or /.history, then we return corresponding resources
109 109
         if path.endswith(SpecialFolderExtension.Archived) and self._show_archive:
110
-            return resources.ArchivedFolder(path, environ, workspace, content)
110
+            return resources.ArchivedFolderResource(path, environ, workspace, content)
111 111
 
112 112
         if path.endswith(SpecialFolderExtension.Deleted) and self._show_delete:
113
-            return resources.DeletedFolder(path, environ, workspace, content)
113
+            return resources.DeletedFolderResource(path, environ, workspace, content)
114 114
 
115 115
         if path.endswith(SpecialFolderExtension.History) and self._show_history:
116 116
             is_deleted_folder = re.search(r'/\.deleted/\.history$', path) is not None
@@ -120,13 +120,13 @@ class Provider(DAVProvider):
120 120
                 else HistoryType.Archived if is_archived_folder \
121 121
                 else HistoryType.Standard
122 122
 
123
-            return resources.HistoryFolder(path, environ, workspace, content, type)
123
+            return resources.HistoryFolderResource(path, environ, workspace, content, type)
124 124
 
125 125
         # Now that's more complicated, we're trying to find out if the path end with /.history/file_name
126 126
         is_history_file_folder = re.search(r'/\.history/([^/]+)$', path) is not None
127 127
 
128 128
         if is_history_file_folder and self._show_history:
129
-            return resources.HistoryFileFolder(
129
+            return resources.HistoryFileFolderResource(
130 130
                 path=path,
131 131
                 environ=environ,
132 132
                 content=content
@@ -143,7 +143,7 @@ class Provider(DAVProvider):
143 143
             content = self.get_content_from_revision(content_revision, content_api)
144 144
 
145 145
             if content.type == ContentType.File:
146
-                return resources.HistoryFile(path, environ, content, content_revision)
146
+                return resources.HistoryFileResource(path, environ, content, content_revision)
147 147
             else:
148 148
                 return resources.HistoryOtherFile(path, environ, content, content_revision)
149 149
 
@@ -153,7 +153,7 @@ class Provider(DAVProvider):
153 153
         if content is None:
154 154
             return None
155 155
         if content.type == ContentType.Folder:
156
-            return resources.Folder(
156
+            return resources.FolderResource(
157 157
                 path=path,
158 158
                 environ=environ,
159 159
                 workspace=content.workspace,
@@ -162,7 +162,7 @@ class Provider(DAVProvider):
162 162
                 user=user,
163 163
             )
164 164
         elif content.type == ContentType.File:
165
-            return resources.File(
165
+            return resources.FileResource(
166 166
                 path=path,
167 167
                 environ=environ,
168 168
                 content=content,
@@ -170,7 +170,7 @@ class Provider(DAVProvider):
170 170
                 user=user
171 171
             )
172 172
         else:
173
-            return resources.OtherFile(
173
+            return resources.OtherFileResource(
174 174
                 path=path,
175 175
                 environ=environ,
176 176
                 content=content,

+ 209 - 84
tracim/lib/webdav/resources.py Целия файл

@@ -74,13 +74,13 @@ class ManageActions(object):
74 74
         transaction.commit()
75 75
 
76 76
 
77
-class Root(DAVCollection):
77
+class RootResource(DAVCollection):
78 78
     """
79
-    Root ressource that represents tracim's home, which contains all workspaces
79
+    RootResource ressource that represents tracim's home, which contains all workspaces
80 80
     """
81 81
 
82 82
     def __init__(self, path: str, environ: dict, user: User, session: Session):
83
-        super(Root, self).__init__(path, environ)
83
+        super(RootResource, self).__init__(path, environ)
84 84
 
85 85
         self.user = user
86 86
         self.session = session
@@ -94,7 +94,7 @@ class Root(DAVCollection):
94 94
         )
95 95
 
96 96
     def __repr__(self) -> str:
97
-        return '<DAVCollection: Root>'
97
+        return '<DAVCollection: RootResource>'
98 98
 
99 99
     def getMemberNames(self) -> [str]:
100 100
         """
@@ -114,7 +114,13 @@ class Root(DAVCollection):
114 114
             workspace = self.workspace_api.get_one_by_label(label)
115 115
             workspace_path = '%s%s%s' % (self.path, '' if self.path == '/' else '/', transform_to_display(workspace.label))
116 116
 
117
-            return Workspace(workspace_path, self.environ, workspace)
117
+            return WorkspaceResource(
118
+                workspace_path,
119
+                self.environ,
120
+                workspace,
121
+                session=self.session,
122
+                user=self.user,
123
+            )
118 124
         except AttributeError:
119 125
             return None
120 126
 
@@ -146,7 +152,13 @@ class Root(DAVCollection):
146 152
         self.path, '' if self.path == '/' else '/', transform_to_display(new_workspace.label))
147 153
 
148 154
         transaction.commit()
149
-        return Workspace(workspace_path, self.environ, new_workspace)
155
+        return WorkspaceResource(
156
+            workspace_path,
157
+            self.environ,
158
+            new_workspace,
159
+            user=self.user,
160
+            session=self.session,
161
+        )
150 162
 
151 163
     def getMemberList(self):
152 164
         """
@@ -158,18 +170,19 @@ class Root(DAVCollection):
158 170
         for workspace in self.workspace_api.get_all():
159 171
             workspace_path = '%s%s%s' % (self.path, '' if self.path == '/' else '/', workspace.label)
160 172
             members.append(
161
-                Workspace(
173
+                WorkspaceResource(
162 174
                     path=workspace_path,
163 175
                     environ=self.environ,
164 176
                     workspace=workspace,
165 177
                     user=self.user,
166
-                    session=self.session)
178
+                    session=self.session,
179
+                )
167 180
             )
168 181
 
169 182
         return members
170 183
 
171 184
 
172
-class Workspace(DAVCollection):
185
+class WorkspaceResource(DAVCollection):
173 186
     """
174 187
     Workspace resource corresponding to tracim's workspaces.
175 188
     Direct children can only be folders, though files might come later on and are supported
@@ -182,7 +195,7 @@ class Workspace(DAVCollection):
182 195
                  user: User,
183 196
                  session: Session
184 197
     ) -> None:
185
-        super(Workspace, self).__init__(path, environ)
198
+        super(WorkspaceResource, self).__init__(path, environ)
186 199
 
187 200
         self.workspace = workspace
188 201
         self.content = None
@@ -262,7 +275,7 @@ class Workspace(DAVCollection):
262 275
             path=self.path + '/' + file_name
263 276
         )
264 277
 
265
-    def createCollection(self, label: str) -> 'Folder':
278
+    def createCollection(self, label: str) -> 'FolderResource':
266 279
         """
267 280
         Create a new folder for the current workspace. As it's not possible for the user to choose
268 281
         which types of content are allowed in this folder, we allow allow all of them.
@@ -292,9 +305,13 @@ class Workspace(DAVCollection):
292 305
 
293 306
         transaction.commit()
294 307
 
295
-        return Folder('%s/%s' % (self.path, transform_to_display(label)),
296
-                      self.environ, folder,
297
-                      self.workspace)
308
+        return FolderResource('%s/%s' % (self.path, transform_to_display(label)),
309
+                              self.environ,
310
+                              content=folder,
311
+                              session=self.session,
312
+                              user=self.user,
313
+                              workspace=self.workspace,
314
+                              )
298 315
 
299 316
     def delete(self):
300 317
         """For now, it is not possible to delete a workspace through the webdav client."""
@@ -320,7 +337,7 @@ class Workspace(DAVCollection):
320 337
 
321 338
             if content.type == ContentType.Folder:
322 339
                 members.append(
323
-                    Folder(
340
+                    FolderResource(
324 341
                         path=content_path,
325 342
                         environ=self.environ,
326 343
                         workspace=self.workspace,
@@ -332,55 +349,68 @@ class Workspace(DAVCollection):
332 349
             elif content.type == ContentType.File:
333 350
                 self._file_count += 1
334 351
                 members.append(
335
-                    File(
352
+                    FileResource(
336 353
                         path=content_path,
337 354
                         environ=self.environ,
338 355
                         content=content,
339 356
                         user=self.user,
340
-                        session=self.session
357
+                        session=self.session,
341 358
                     )
342 359
                 )
343 360
             else:
344 361
                 self._file_count += 1
345
-                members.append(OtherFile(content_path, self.environ, content))
362
+                members.append(
363
+                    OtherFileResource(
364
+                        content_path,
365
+                        self.environ,
366
+                        content,
367
+                        session=self.session,
368
+                        user=self.user,
369
+                    ))
346 370
 
347 371
         if self._file_count > 0 and self.provider.show_history():
348 372
             members.append(
349
-                HistoryFolder(
373
+                HistoryFolderResource(
350 374
                     path=self.path + '/' + ".history",
351 375
                     environ=self.environ,
352 376
                     content=self.content,
353 377
                     workspace=self.workspace,
354
-                    type=HistoryType.Standard
378
+                    type=HistoryType.Standard,
379
+                    session=self.session,
380
+                    user=self.user,
355 381
                 )
356 382
             )
357 383
 
358 384
         if self.provider.show_delete():
359 385
             members.append(
360
-                DeletedFolder(
386
+                DeletedFolderResource(
361 387
                     path=self.path + '/' + ".deleted",
362 388
                     environ=self.environ,
363 389
                     content=self.content,
364
-                    workspace=self.workspace
390
+                    workspace=self.workspace,
391
+                    session=self.session,
392
+                    user=self.user,
365 393
                 )
366 394
             )
367 395
 
368 396
         if self.provider.show_archive():
369 397
             members.append(
370
-                ArchivedFolder(
398
+                ArchivedFolderResource(
371 399
                     path=self.path + '/' + ".archived",
372 400
                     environ=self.environ,
373 401
                     content=self.content,
374
-                    workspace=self.workspace
402
+                    workspace=self.workspace,
403
+                    user=self.user,
404
+                    session=self.session,
375 405
                 )
376 406
             )
377 407
 
378 408
         return members
379 409
 
380 410
 
381
-class Folder(Workspace):
411
+class FolderResource(WorkspaceResource):
382 412
     """
383
-    Folder resource corresponding to tracim's folders.
413
+    FolderResource resource corresponding to tracim's folders.
384 414
     Direct children can only be either folder, files, pages or threads
385 415
     By default when creating new folders, we allow them to contain all types of content
386 416
     """
@@ -394,7 +424,7 @@ class Folder(Workspace):
394 424
             user: User,
395 425
             session: Session
396 426
     ):
397
-        super(Folder, self).__init__(
427
+        super(FolderResource, self).__init__(
398 428
             path=path,
399 429
             environ=environ,
400 430
             workspace=workspace,
@@ -482,7 +512,10 @@ class Folder(Workspace):
482 512
 
483 513
     def move_folder(self, destpath):
484 514
 
485
-        workspace_api = WorkspaceApi(self.user)
515
+        workspace_api = WorkspaceApi(
516
+            current_user=self.user,
517
+            session=self.session,
518
+        )
486 519
         workspace = self.provider.get_workspace_from_path(
487 520
             normpath(destpath), workspace_api
488 521
         )
@@ -493,7 +526,11 @@ class Folder(Workspace):
493 526
             workspace
494 527
         )
495 528
 
496
-        with new_revision(self.content):
529
+        with new_revision(
530
+            content=self.content,
531
+            tm=transaction.manager,
532
+            session=self.session,
533
+        ):
497 534
             if basename(destpath) != self.getDisplayName():
498 535
                 self.content_api.update_content(self.content, transform_to_bdd(basename(destpath)))
499 536
                 self.content_api.save(self.content)
@@ -524,7 +561,7 @@ class Folder(Workspace):
524 561
             try:
525 562
                 if content.type == ContentType.Folder:
526 563
                     members.append(
527
-                        Folder(
564
+                        FolderResource(
528 565
                             path=content_path,
529 566
                             environ=self.environ,
530 567
                             workspace=self.workspace,
@@ -536,7 +573,7 @@ class Folder(Workspace):
536 573
                 elif content.type == ContentType.File:
537 574
                     self._file_count += 1
538 575
                     members.append(
539
-                        File(
576
+                        FileResource(
540 577
                             path=content_path,
541 578
                             environ=self.environ,
542 579
                             content=content,
@@ -546,7 +583,7 @@ class Folder(Workspace):
546 583
                 else:
547 584
                     self._file_count += 1
548 585
                     members.append(
549
-                        OtherFile(
586
+                        OtherFileResource(
550 587
                             path=content_path,
551 588
                             environ=self.environ,
552 589
                             content=content,
@@ -563,39 +600,48 @@ class Folder(Workspace):
563 600
 
564 601
         if self._file_count > 0 and self.provider.show_history():
565 602
             members.append(
566
-                HistoryFolder(
603
+                HistoryFolderResource(
567 604
                     path=self.path + '/' + ".history",
568 605
                     environ=self.environ,
569 606
                     content=self.content,
570 607
                     workspace=self.workspace,
571
-                    type=HistoryType.Standard
608
+                    type=HistoryType.Standard,
609
+                    user=self.user,
610
+                    session=self.session,
572 611
                 )
573 612
             )
574 613
 
575 614
         if self.provider.show_delete():
576 615
             members.append(
577
-                DeletedFolder(
616
+                DeletedFolderResource(
578 617
                     path=self.path + '/' + ".deleted",
579 618
                     environ=self.environ,
580 619
                     content=self.content,
581
-                    workspace=self.workspace
620
+                    workspace=self.workspace,
621
+                    user=self.user,
622
+                    session=self.session,
582 623
                 )
583 624
             )
584 625
 
585 626
         if self.provider.show_archive():
586 627
             members.append(
587
-                ArchivedFolder(
628
+                ArchivedFolderResource(
588 629
                     path=self.path + '/' + ".archived",
589 630
                     environ=self.environ,
590 631
                     content=self.content,
591
-                    workspace=self.workspace
632
+                    workspace=self.workspace,
633
+                    user=self.user,
634
+                    session=self.session,
592 635
                 )
593 636
             )
594 637
 
595 638
         return members
596 639
 
640
+# TODO - G.M - 02-05-2018 - Check these object (History/Deleted/Archived Folder)
641
+# Those object are now not in used by tracim and also not tested,
642
+
597 643
 
598
-class HistoryFolder(Folder):
644
+class HistoryFolderResource(FolderResource):
599 645
     """
600 646
     A virtual resource which contains a sub-folder for every files (DAVNonCollection) contained in the parent
601 647
     folder
@@ -610,7 +656,7 @@ class HistoryFolder(Folder):
610 656
                  content: Content=None,
611 657
                  type: str=HistoryType.Standard
612 658
     ) -> None:
613
-        super(HistoryFolder, self).__init__(
659
+        super(HistoryFolderResource, self).__init__(
614 660
             path=path,
615 661
             environ=environ,
616 662
             workspace=workspace,
@@ -625,11 +671,13 @@ class HistoryFolder(Folder):
625 671
         self.content_api = ContentApi(
626 672
             current_user=self.user,
627 673
             show_archived=self._is_archived,
628
-            show_deleted=self._is_deleted
674
+            show_deleted=self._is_deleted,
675
+            session=self.session,
676
+            config=self.provider.app_config,
629 677
         )
630 678
 
631 679
     def __repr__(self) -> str:
632
-        return "<DAVCollection: HistoryFolder (%s)>" % self.content.file_name
680
+        return "<DAVCollection: HistoryFolderResource (%s)>" % self.content.file_name
633 681
 
634 682
     def getCreationDate(self) -> float:
635 683
         return mktime(datetime.now().timetuple())
@@ -646,10 +694,13 @@ class HistoryFolder(Folder):
646 694
             content_parent=self.content
647 695
         )
648 696
 
649
-        return HistoryFileFolder(
697
+        return HistoryFileFolderResource(
650 698
             path='%s/%s' % (self.path, content.get_label_as_file()),
651 699
             environ=self.environ,
652
-            content=content)
700
+            content=content,
701
+            session=self.session,
702
+            user=self.user,
703
+        )
653 704
 
654 705
     def getMemberNames(self) -> [str]:
655 706
         ret = []
@@ -692,15 +743,18 @@ class HistoryFolder(Folder):
692 743
         
693 744
         for content in children:
694 745
             if content.is_archived == self._is_archived and content.is_deleted == self._is_deleted:
695
-                members.append(HistoryFileFolder(
746
+                members.append(HistoryFileFolderResource(
696 747
                     path='%s/%s' % (self.path, content.get_label_as_file()),
697 748
                     environ=self.environ,
698
-                    content=content))
749
+                    content=content,
750
+                    user=self.user,
751
+                    session=self.session,
752
+                ))
699 753
 
700 754
         return members
701 755
 
702 756
 
703
-class DeletedFolder(HistoryFolder):
757
+class DeletedFolderResource(HistoryFolderResource):
704 758
     """
705 759
     A virtual resources which exists for every folder or workspaces which contains their deleted children
706 760
     """
@@ -714,7 +768,7 @@ class DeletedFolder(HistoryFolder):
714 768
             session: Session,
715 769
             content: Content=None
716 770
     ):
717
-        super(DeletedFolder, self).__init__(
771
+        super(DeletedFolderResource, self).__init__(
718 772
             path=path,
719 773
             environ=environ,
720 774
             workspace=workspace,
@@ -727,7 +781,7 @@ class DeletedFolder(HistoryFolder):
727 781
         self._file_count = 0
728 782
 
729 783
     def __repr__(self):
730
-        return "<DAVCollection: DeletedFolder (%s)" % self.content.file_name
784
+        return "<DAVCollection: DeletedFolderResource (%s)" % self.content.file_name
731 785
 
732 786
     def getCreationDate(self) -> float:
733 787
         return mktime(datetime.now().timetuple())
@@ -780,30 +834,54 @@ class DeletedFolder(HistoryFolder):
780 834
                 content_path = '%s/%s' % (self.path, transform_to_display(content.get_label_as_file()))
781 835
 
782 836
                 if content.type == ContentType.Folder:
783
-                    members.append(Folder(content_path, self.environ, self.workspace, content))
837
+                    members.append(
838
+                        FolderResource(
839
+                            content_path,
840
+                            self.environ,
841
+                            self.workspace,
842
+                            content,
843
+                            user=self.user,
844
+                            session=self.session,
845
+                        ))
784 846
                 elif content.type == ContentType.File:
785 847
                     self._file_count += 1
786
-                    members.append(File(content_path, self.environ, content))
848
+                    members.append(
849
+                        FileResource(
850
+                            content_path,
851
+                            self.environ,
852
+                            content,
853
+                            user=self.user,
854
+                            session=self.session,
855
+                        )
856
+                    )
787 857
                 else:
788 858
                     self._file_count += 1
789
-                    members.append(OtherFile(content_path, self.environ, content))
859
+                    members.append(
860
+                        OtherFileResource(
861
+                            content_path,
862
+                            self.environ,
863
+                            content,
864
+                            user=self.user,
865
+                            session=self.session,
866
+                    ))
790 867
 
791 868
         if self._file_count > 0 and self.provider.show_history():
792 869
             members.append(
793
-                HistoryFolder(
870
+                HistoryFolderResource(
794 871
                     path=self.path + '/' + ".history",
795 872
                     environ=self.environ,
796 873
                     content=self.content,
797 874
                     workspace=self.workspace,
798 875
                     user=self.user,
799 876
                     type=HistoryType.Standard,
877
+                    session=self.session,
800 878
                 )
801 879
             )
802 880
 
803 881
         return members
804 882
 
805 883
 
806
-class ArchivedFolder(HistoryFolder):
884
+class ArchivedFolderResource(HistoryFolderResource):
807 885
     """
808 886
     A virtual resources which exists for every folder or workspaces which contains their archived children
809 887
     """
@@ -816,7 +894,7 @@ class ArchivedFolder(HistoryFolder):
816 894
             session: Session,
817 895
             content: Content=None
818 896
     ):
819
-        super(ArchivedFolder, self).__init__(
897
+        super(ArchivedFolderResource, self).__init__(
820 898
             path=path,
821 899
             environ=environ,
822 900
             workspace=workspace,
@@ -829,7 +907,7 @@ class ArchivedFolder(HistoryFolder):
829 907
         self._file_count = 0
830 908
 
831 909
     def __repr__(self) -> str:
832
-        return "<DAVCollection: ArchivedFolder (%s)" % self.content.file_name
910
+        return "<DAVCollection: ArchivedFolderResource (%s)" % self.content.file_name
833 911
 
834 912
     def getCreationDate(self) -> float:
835 913
         return mktime(datetime.now().timetuple())
@@ -877,30 +955,53 @@ class ArchivedFolder(HistoryFolder):
877 955
                 content_path = '%s/%s' % (self.path, transform_to_display(content.get_label_as_file()))
878 956
 
879 957
                 if content.type == ContentType.Folder:
880
-                    members.append(Folder(content_path, self.environ, self.workspace, content))
958
+                    members.append(
959
+                        FolderResource(
960
+                            content_path,
961
+                            self.environ,
962
+                            self.workspace,
963
+                            content,
964
+                            user=self.user,
965
+                            session=self.session,
966
+                        ))
881 967
                 elif content.type == ContentType.File:
882 968
                     self._file_count += 1
883
-                    members.append(File(content_path, self.environ, content))
969
+                    members.append(
970
+                        FileResource(
971
+                            content_path,
972
+                            self.environ,
973
+                            content,
974
+                            user=self.user,
975
+                            session=self.session,
976
+                        ))
884 977
                 else:
885 978
                     self._file_count += 1
886
-                    members.append(OtherFile(content_path, self.environ, content))
979
+                    members.append(
980
+                        OtherFileResource(
981
+                            content_path,
982
+                            self.environ,
983
+                            content,
984
+                            user=self.user,
985
+                            session=self.session,
986
+                        ))
887 987
 
888 988
         if self._file_count > 0 and self.provider.show_history():
889 989
             members.append(
890
-                HistoryFolder(
990
+                HistoryFolderResource(
891 991
                     path=self.path + '/' + ".history",
892 992
                     environ=self.environ,
893 993
                     content=self.content,
894 994
                     workspace=self.workspace,
895 995
                     user=self.user,
896
-                    type=HistoryType.Standard
996
+                    type=HistoryType.Standard,
997
+                    session=self.session,
897 998
                 )
898 999
             )
899 1000
 
900 1001
         return members
901 1002
 
902 1003
 
903
-class HistoryFileFolder(HistoryFolder):
1004
+class HistoryFileFolderResource(HistoryFolderResource):
904 1005
     """
905 1006
     A virtual resource that contains for a given content (file/page/thread) all its revisions
906 1007
     """
@@ -913,7 +1014,7 @@ class HistoryFileFolder(HistoryFolder):
913 1014
             user: User,
914 1015
             session: Session
915 1016
     ) -> None:
916
-        super(HistoryFileFolder, self).__init__(
1017
+        super(HistoryFileFolderResource, self).__init__(
917 1018
             path=path,
918 1019
             environ=environ,
919 1020
             workspace=content.workspace,
@@ -924,7 +1025,7 @@ class HistoryFileFolder(HistoryFolder):
924 1025
         )
925 1026
 
926 1027
     def __repr__(self) -> str:
927
-        return "<DAVCollection: HistoryFileFolder (%s)" % self.content.file_name
1028
+        return "<DAVCollection: HistoryFileFolderResource (%s)" % self.content.file_name
928 1029
 
929 1030
     def getDisplayName(self) -> str:
930 1031
         return self.content.get_label_as_file()
@@ -951,17 +1052,23 @@ class HistoryFileFolder(HistoryFolder):
951 1052
         left_side = '%s/(%d - %s) ' % (self.path, revision.revision_id, revision.revision_type)
952 1053
 
953 1054
         if self.content.type == ContentType.File:
954
-            return HistoryFile(
1055
+            return HistoryFileResource(
955 1056
                 path='%s%s' % (left_side, transform_to_display(revision.file_name)),
956 1057
                 environ=self.environ,
957 1058
                 content=self.content,
958
-                content_revision=revision)
1059
+                content_revision=revision,
1060
+                session=self.session,
1061
+                user=self.user,
1062
+            )
959 1063
         else:
960 1064
             return HistoryOtherFile(
961 1065
                 path='%s%s' % (left_side, transform_to_display(revision.get_label_as_file())),
962 1066
                 environ=self.environ,
963 1067
                 content=self.content,
964
-                content_revision=revision)
1068
+                content_revision=revision,
1069
+                session=self.session,
1070
+                user=self.user,
1071
+            )
965 1072
 
966 1073
     def getMemberList(self) -> [_DAVResource]:
967 1074
         members = []
@@ -971,26 +1078,32 @@ class HistoryFileFolder(HistoryFolder):
971 1078
             left_side = '%s/(%d - %s) ' % (self.path, content.revision_id, content.revision_type)
972 1079
 
973 1080
             if self.content.type == ContentType.File:
974
-                members.append(HistoryFile(
1081
+                members.append(HistoryFileResource(
975 1082
                     path='%s%s' % (left_side, transform_to_display(content.file_name)),
976 1083
                     environ=self.environ,
977 1084
                     content=self.content,
978
-                    content_revision=content)
1085
+                    content_revision=content,
1086
+                    user=self.user,
1087
+                    session=self.session,
1088
+                    )
979 1089
                 )
980 1090
             else:
981 1091
                 members.append(HistoryOtherFile(
982 1092
                     path='%s%s' % (left_side, transform_to_display(content.file_name)),
983 1093
                     environ=self.environ,
984 1094
                     content=self.content,
985
-                    content_revision=content)
1095
+                    content_revision=content,
1096
+                    user=self.user,
1097
+                    session=self.session,
1098
+                    )
986 1099
                 )
987 1100
 
988 1101
         return members
989 1102
 
990 1103
 
991
-class File(DAVNonCollection):
1104
+class FileResource(DAVNonCollection):
992 1105
     """
993
-    File resource corresponding to tracim's files
1106
+    FileResource resource corresponding to tracim's files
994 1107
     """
995 1108
     def __init__(
996 1109
             self,
@@ -1000,7 +1113,7 @@ class File(DAVNonCollection):
1000 1113
             user: User,
1001 1114
             session: Session,
1002 1115
     ) -> None:
1003
-        super(File, self).__init__(path, environ)
1116
+        super(FileResource, self).__init__(path, environ)
1004 1117
 
1005 1118
         self.content = content
1006 1119
         self.user = user
@@ -1016,7 +1129,7 @@ class File(DAVNonCollection):
1016 1129
         # self.setPropertyValue('Win32FileAttributes', '00000021')
1017 1130
 
1018 1131
     def __repr__(self) -> str:
1019
-        return "<DAVNonCollection: File (%d)>" % self.content.revision_id
1132
+        return "<DAVNonCollection: FileResource (%d)>" % self.content.revision_id
1020 1133
 
1021 1134
     def getContentLength(self) -> int:
1022 1135
         return self.content.depot_file.file.content_length
@@ -1230,16 +1343,16 @@ class File(DAVNonCollection):
1230 1343
         ).action()
1231 1344
 
1232 1345
 
1233
-class HistoryFile(File):
1346
+class HistoryFileResource(FileResource):
1234 1347
     """
1235 1348
     A virtual resource corresponding to a specific tracim's revision's file
1236 1349
     """
1237 1350
     def __init__(self, path: str, environ: dict, content: Content, user: User, session: Session, content_revision: ContentRevisionRO):
1238
-        super(HistoryFile, self).__init__(path, environ, content, user=user, session=session)
1351
+        super(HistoryFileResource, self).__init__(path, environ, content, user=user, session=session)
1239 1352
         self.content_revision = content_revision
1240 1353
 
1241 1354
     def __repr__(self) -> str:
1242
-        return "<DAVNonCollection: HistoryFile (%s-%s)" % (self.content.content_id, self.content.file_name)
1355
+        return "<DAVNonCollection: HistoryFileResource (%s-%s)" % (self.content.content_id, self.content.file_name)
1243 1356
 
1244 1357
     def getDisplayName(self) -> str:
1245 1358
         left_side = '(%d - %s) ' % (self.content_revision.revision_id, self.content_revision.revision_type)
@@ -1268,12 +1381,12 @@ class HistoryFile(File):
1268 1381
         raise DAVError(HTTP_FORBIDDEN)
1269 1382
 
1270 1383
 
1271
-class OtherFile(File):
1384
+class OtherFileResource(FileResource):
1272 1385
     """
1273
-    File resource corresponding to tracim's page and thread
1386
+    FileResource resource corresponding to tracim's page and thread
1274 1387
     """
1275 1388
     def __init__(self, path: str, environ: dict, content: Content, user:User, session: Session):
1276
-        super(OtherFile, self).__init__(path, environ, content, user=user, session=session)
1389
+        super(OtherFileResource, self).__init__(path, environ, content, user=user, session=session)
1277 1390
 
1278 1391
         self.content_revision = self.content.revision
1279 1392
 
@@ -1292,7 +1405,7 @@ class OtherFile(File):
1292 1405
         return self.path
1293 1406
 
1294 1407
     def __repr__(self) -> str:
1295
-        return "<DAVNonCollection: OtherFile (%s)" % self.content.file_name
1408
+        return "<DAVNonCollection: OtherFileResource (%s)" % self.content.file_name
1296 1409
 
1297 1410
     def getContentLength(self) -> int:
1298 1411
         return len(self.content_designed)
@@ -1318,12 +1431,24 @@ class OtherFile(File):
1318 1431
             )
1319 1432
 
1320 1433
 
1321
-class HistoryOtherFile(OtherFile):
1434
+class HistoryOtherFile(OtherFileResource):
1322 1435
     """
1323 1436
     A virtual resource corresponding to a specific tracim's revision's page and thread
1324 1437
     """
1325
-    def __init__(self, path: str, environ: dict, content: Content, user:User, content_revision: ContentRevisionRO):
1326
-        super(HistoryOtherFile, self).__init__(path, environ, content, user=user, session=self.session)
1438
+    def __init__(self,
1439
+                 path: str,
1440
+                 environ: dict,
1441
+                 content: Content,
1442
+                 user:User,
1443
+                 content_revision: ContentRevisionRO,
1444
+                 session: Session):
1445
+        super(HistoryOtherFile, self).__init__(
1446
+            path,
1447
+            environ,
1448
+            content,
1449
+            user=user,
1450
+            session=session
1451
+        )
1327 1452
         self.content_revision = content_revision
1328 1453
         self.content_designed = self.design()
1329 1454
 

+ 14 - 1
tracim/models/__init__.py Целия файл

@@ -48,8 +48,21 @@ def get_tm_session(session_factory, transaction_manager):
48 48
 
49 49
     """
50 50
     dbsession = session_factory()
51
+    # FIXME - G.M - 02-05-2018 - Check Zope/Sqlalchemy session conf.
52
+    # We use both keep_session=True for zope and
53
+    # expire_on_commit=False for sessionmaker to keep session alive after
54
+    # commit ( in order  to not have trouble like
55
+    # https://github.com/tracim/tracim_backend/issues/52
56
+    # or detached objects problems).
57
+    # These problem happened because we use "commit" in our current code.
58
+    # Understand what those params really mean and check if it can cause
59
+    # troubles somewhere else.
60
+    # see https://stackoverflow.com/questions/16152241/how-to-get-a-sqlalchemy-session-managed-by-zope-transaction-that-has-the-same-sc  # nopep8
51 61
     zope.sqlalchemy.register(
52
-        dbsession, transaction_manager=transaction_manager)
62
+        dbsession,
63
+        transaction_manager=transaction_manager,
64
+        keep_session=True,
65
+    )
53 66
     listen(dbsession, 'before_flush', prevent_content_revision_delete)
54 67
     return dbsession
55 68
 

+ 9 - 13
tracim/tests/library/test_webdav.py Целия файл

@@ -8,7 +8,7 @@ from tracim.lib.core.user import UserApi
8 8
 from tracim.tests import eq_
9 9
 from tracim.lib.core.notifications import DummyNotifier
10 10
 from tracim.lib.webdav.dav_provider import Provider
11
-from tracim.lib.webdav.resources import Root
11
+from tracim.lib.webdav.resources import RootResource
12 12
 from tracim.models import Content
13 13
 from tracim.models import ContentRevisionRO
14 14
 from tracim.tests import StandardTest
@@ -88,8 +88,8 @@ class TestWebDav(StandardTest):
88 88
                 'bob@fsf.local',
89 89
             )
90 90
         )
91
-        assert root, 'Path / should return a Root instance'
92
-        assert isinstance(root, Root)
91
+        assert root, 'Path / should return a RootResource instance'
92
+        assert isinstance(root, RootResource)
93 93
 
94 94
     def test_unit__list_workspaces_with_user__ok(self):
95 95
         provider = self._get_provider(self.app_config)
@@ -100,14 +100,14 @@ class TestWebDav(StandardTest):
100 100
                 'bob@fsf.local',
101 101
             )
102 102
         )
103
-        assert root, 'Path / should return a Root instance'
104
-        assert isinstance(root, Root), 'Path / should return a Root instance'
103
+        assert root, 'Path / should return a RootResource instance'
104
+        assert isinstance(root, RootResource), 'Path / should return a RootResource instance'
105 105
 
106 106
         children = root.getMemberList()
107 107
         eq_(
108 108
             2,
109 109
             len(children),
110
-            msg='Root should return 2 workspaces instead {0}'.format(
110
+            msg='RootResource should return 2 workspaces instead {0}'.format(
111 111
                 len(children),
112 112
             )
113 113
         )
@@ -130,14 +130,14 @@ class TestWebDav(StandardTest):
130 130
                 'admin@admin.admin',
131 131
             )
132 132
         )
133
-        assert root, 'Path / should return a Root instance'
134
-        assert isinstance(root, Root), 'Path / should return a Root instance'
133
+        assert root, 'Path / should return a RootResource instance'
134
+        assert isinstance(root, RootResource), 'Path / should return a RootResource instance'
135 135
 
136 136
         children = root.getMemberList()
137 137
         eq_(
138 138
             2,
139 139
             len(children),
140
-            msg='Root should return 2 workspaces instead {0}'.format(
140
+            msg='RootResource should return 2 workspaces instead {0}'.format(
141 141
                 len(children),
142 142
             )
143 143
         )
@@ -311,8 +311,6 @@ class TestWebDav(StandardTest):
311 311
             )
312 312
         )
313 313
 
314
-    @pytest.mark.xfail(raises=InvalidRequestError,
315
-                       reason='Sqlalchemy session and transaction bug')
316 314
     def test_unit__create_delete_and_create_file__ok(self):
317 315
         provider = self._get_provider(self.app_config)
318 316
         environ = self._get_environ(
@@ -559,8 +557,6 @@ class TestWebDav(StandardTest):
559 557
                 content_to_move.parent.label
560 558
         )
561 559
 
562
-    @pytest.mark.xfail(raises=InvalidRequestError,
563
-                       reason='Sqlalchemy session and transaction bug')
564 560
     def test_unit__update_content__ok(self):
565 561
         provider = self._get_provider(self.app_config)
566 562
         environ = self._get_environ(