Browse Source

Merge pull request #96 from tracim/fix/621_add_worskpace_filter_by_content_type

inkhey 5 years ago
parent
commit
fbadc4b9c4
No account linked to committer's email

+ 6 - 4
tracim/lib/core/content.py View File

@@ -726,13 +726,15 @@ class ContentApi(object):
726 726
 
727 727
     def get_all(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> typing.List[Content]:
728 728
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
729
-        assert content_type is not None# DYN_REMOVE
730
-        assert isinstance(content_type, str) # DYN_REMOVE
731
-
729
+        if not content_type:
730
+            content_type = ContentType.Any
732 731
         resultset = self._base_query(workspace)
733 732
 
734 733
         if content_type!=ContentType.Any:
735
-            resultset = resultset.filter(Content.type==content_type)
734
+            # INFO - G.M - 2018-07-05 - convert with
735
+            #  content type object to support legacy slug
736
+            content_type_object = ContentType(content_type)
737
+            resultset = resultset.filter(Content.type.in_(content_type_object.get_slug_aliases()))
736 738
 
737 739
         if parent_id:
738 740
             resultset = resultset.filter(Content.parent_id==parent_id)

+ 22 - 0
tracim/models/contents.py View File

@@ -251,6 +251,19 @@ class ContentTypeLegacy(NewContentType):
251 251
                 return
252 252
         raise ContentTypeNotExist()
253 253
 
254
+    def get_slug_aliases(self) -> typing.List[str]:
255
+        """
256
+        Get all slug aliases of a content,
257
+        useful for legacy code convertion
258
+        """
259
+        # TODO - G.M - 2018-07-05 - Remove this legacy compat code
260
+        # when possible.
261
+        page_alias = [self.Page, self.PageLegacy]
262
+        if self.slug in page_alias:
263
+            return page_alias
264
+        else:
265
+            return [self.slug]
266
+
254 267
     @classmethod
255 268
     def all(cls) -> typing.List[str]:
256 269
         return cls.allowed_types()
@@ -261,6 +274,15 @@ class ContentTypeLegacy(NewContentType):
261 274
         return contents_types
262 275
 
263 276
     @classmethod
277
+    def allowed_type_values(cls) -> typing.List[str]:
278
+        """
279
+        All content type slug + special values like any
280
+        """
281
+        content_types = cls.allowed_types()
282
+        content_types.append(ContentTypeLegacy.Any)
283
+        return content_types
284
+
285
+    @classmethod
264 286
     def allowed_types_for_folding(cls):
265 287
         # This method is used for showing only "main"
266 288
         # types in the left-side treeview

+ 2 - 0
tracim/models/context_models.py View File

@@ -68,11 +68,13 @@ class ContentFilter(object):
68 68
             show_archived: int = 0,
69 69
             show_deleted: int = 0,
70 70
             show_active: int = 1,
71
+            content_type: str = None,
71 72
     ) -> None:
72 73
         self.parent_id = parent_id
73 74
         self.show_archived = bool(show_archived)
74 75
         self.show_deleted = bool(show_deleted)
75 76
         self.show_active = bool(show_active)
77
+        self.content_type = content_type
76 78
 
77 79
 
78 80
 class ContentCreation(object):

+ 247 - 0
tracim/tests/functional/test_workspaces.py View File

@@ -2,6 +2,15 @@
2 2
 """
3 3
 Tests for /api/v2/workspaces subpath endpoints.
4 4
 """
5
+
6
+import transaction
7
+from depot.io.utils import FileIntent
8
+
9
+from tracim import models
10
+from tracim.lib.core.content import ContentApi
11
+from tracim.lib.core.workspace import WorkspaceApi
12
+from tracim.models import get_tm_session
13
+from tracim.models.data import ContentType
5 14
 from tracim.tests import FunctionalTest
6 15
 from tracim.tests import set_html_document_slug_to_legacy
7 16
 from tracim.fixtures.content import Content as ContentFixtures
@@ -241,6 +250,7 @@ class TestWorkspaceContents(FunctionalTest):
241 250
         assert len(res) == 3
242 251
         content = res[0]
243 252
         assert content['content_id'] == 1
253
+        assert content['content_type'] == 'folder'
244 254
         assert content['is_archived'] is False
245 255
         assert content['is_deleted'] is False
246 256
         assert content['label'] == 'Tools'
@@ -252,6 +262,7 @@ class TestWorkspaceContents(FunctionalTest):
252 262
         assert content['workspace_id'] == 1
253 263
         content = res[1]
254 264
         assert content['content_id'] == 2
265
+        assert content['content_type'] == 'folder'
255 266
         assert content['is_archived'] is False
256 267
         assert content['is_deleted'] is False
257 268
         assert content['label'] == 'Menus'
@@ -263,6 +274,37 @@ class TestWorkspaceContents(FunctionalTest):
263 274
         assert content['workspace_id'] == 1
264 275
         content = res[2]
265 276
         assert content['content_id'] == 11
277
+        assert content['content_type'] == 'html-documents'
278
+        assert content['is_archived'] is False
279
+        assert content['is_deleted'] is False
280
+        assert content['label'] == 'Current Menu'
281
+        assert content['parent_id'] == 2
282
+        assert content['show_in_ui'] is True
283
+        assert content['slug'] == 'current-menu'
284
+        assert content['status'] == 'open'
285
+        assert set(content['sub_content_types']) == {'thread', 'html-documents', 'folder', 'file'}  # nopep8
286
+        assert content['workspace_id'] == 1
287
+
288
+    def test_api__get_workspace_content__ok_200__get_default_html_documents(self):
289
+        """
290
+        Check obtain workspace contents with defaults filters + content_filter
291
+        """
292
+        self.testapp.authorization = (
293
+            'Basic',
294
+            (
295
+                'admin@admin.admin',
296
+                'admin@admin.admin'
297
+            )
298
+        )
299
+        params = {
300
+            'content_type': 'html-documents',
301
+        }
302
+        res = self.testapp.get('/api/v2/workspaces/1/contents', status=200, params=params).json_body   # nopep8
303
+        assert len(res) == 1
304
+        content = res[0]
305
+        assert content
306
+        assert content['content_id'] == 11
307
+        assert content['content_type'] == 'html-documents'
266 308
         assert content['is_archived'] is False
267 309
         assert content['is_deleted'] is False
268 310
         assert content['label'] == 'Current Menu'
@@ -539,6 +581,210 @@ class TestWorkspaceContents(FunctionalTest):
539 581
         assert res == []
540 582
 
541 583
     # Folder related
584
+    def test_api__get_workspace_content__ok_200__get_all_filter_content_thread(self):
585
+        # prepare data
586
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
587
+        admin = dbsession.query(models.User) \
588
+            .filter(models.User.email == 'admin@admin.admin') \
589
+            .one()
590
+        workspace_api = WorkspaceApi(
591
+            current_user=admin,
592
+            session=dbsession,
593
+            config=self.app_config
594
+        )
595
+        business_workspace = workspace_api.get_one(1)
596
+        content_api = ContentApi(
597
+            current_user=admin,
598
+            session=dbsession,
599
+            config=self.app_config
600
+        )
601
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
602
+        test_thread = content_api.create(
603
+            content_type=ContentType.Thread,
604
+            workspace=business_workspace,
605
+            parent=tool_folder,
606
+            label='Test Thread',
607
+            do_save=False,
608
+            do_notify=False,
609
+        )
610
+        test_thread.description = 'Thread description'
611
+        dbsession.add(test_thread)
612
+        test_file = content_api.create(
613
+            content_type=ContentType.File,
614
+            workspace=business_workspace,
615
+            parent=tool_folder,
616
+            label='Test file',
617
+            do_save=False,
618
+            do_notify=False,
619
+        )
620
+        test_file.file_extension = '.txt'
621
+        test_file.depot_file = FileIntent(
622
+            b'Test file',
623
+            'Test_file.txt',
624
+            'text/plain',
625
+        )
626
+        test_page_legacy = content_api.create(
627
+            content_type=ContentType.Page,
628
+            workspace=business_workspace,
629
+            label='test_page',
630
+            do_save=False,
631
+            do_notify=False,
632
+        )
633
+        test_page_legacy.type = ContentType.PageLegacy
634
+        content_api.update_content(test_page_legacy, 'test_page', '<p>PAGE</p>')
635
+        test_html_document = content_api.create(
636
+            content_type=ContentType.Page,
637
+            workspace=business_workspace,
638
+            label='test_html_page',
639
+            do_save=False,
640
+            do_notify=False,
641
+        )
642
+        content_api.update_content(test_html_document, 'test_page', '<p>HTML_DOCUMENT</p>')  # nopep8
643
+        dbsession.flush()
644
+        transaction.commit()
645
+        # test-itself
646
+        params = {
647
+            'parent_id': 1,
648
+            'show_archived': 1,
649
+            'show_deleted': 1,
650
+            'show_active': 1,
651
+            'content_type': 'thread',
652
+        }
653
+        self.testapp.authorization = (
654
+            'Basic',
655
+            (
656
+                'admin@admin.admin',
657
+                'admin@admin.admin'
658
+            )
659
+        )
660
+        res = self.testapp.get(
661
+            '/api/v2/workspaces/1/contents',
662
+            status=200,
663
+            params=params,
664
+        ).json_body
665
+        assert len(res) == 1
666
+        content = res[0]
667
+        assert content['content_type'] == 'thread'
668
+        assert content['content_id']
669
+        assert content['is_archived'] is False
670
+        assert content['is_deleted'] is False
671
+        assert content['label'] == 'Test Thread'
672
+        assert content['parent_id'] == 1
673
+        assert content['show_in_ui'] is True
674
+        assert content['slug'] == 'test-thread'
675
+        assert content['status'] == 'open'
676
+        assert set(content['sub_content_types']) == {'thread', 'html-documents', 'folder', 'file'}  # nopep8
677
+        assert content['workspace_id'] == 1
678
+
679
+    def test_api__get_workspace_content__ok_200__get_all_filter_content_html_and_legacy_page(self):  # nopep8
680
+        # prepare data
681
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
682
+        admin = dbsession.query(models.User) \
683
+            .filter(models.User.email == 'admin@admin.admin') \
684
+            .one()
685
+        workspace_api = WorkspaceApi(
686
+            current_user=admin,
687
+            session=dbsession,
688
+            config=self.app_config
689
+        )
690
+        business_workspace = workspace_api.get_one(1)
691
+        content_api = ContentApi(
692
+            current_user=admin,
693
+            session=dbsession,
694
+            config=self.app_config
695
+        )
696
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
697
+        test_thread = content_api.create(
698
+            content_type=ContentType.Thread,
699
+            workspace=business_workspace,
700
+            parent=tool_folder,
701
+            label='Test Thread',
702
+            do_save=False,
703
+            do_notify=False,
704
+        )
705
+        test_thread.description = 'Thread description'
706
+        dbsession.add(test_thread)
707
+        test_file = content_api.create(
708
+            content_type=ContentType.File,
709
+            workspace=business_workspace,
710
+            parent=tool_folder,
711
+            label='Test file',
712
+            do_save=False,
713
+            do_notify=False,
714
+        )
715
+        test_file.file_extension = '.txt'
716
+        test_file.depot_file = FileIntent(
717
+            b'Test file',
718
+            'Test_file.txt',
719
+            'text/plain',
720
+        )
721
+        test_page_legacy = content_api.create(
722
+            content_type=ContentType.Page,
723
+            workspace=business_workspace,
724
+            parent=tool_folder,
725
+            label='test_page',
726
+            do_save=False,
727
+            do_notify=False,
728
+        )
729
+        test_page_legacy.type = ContentType.PageLegacy
730
+        content_api.update_content(test_page_legacy, 'test_page', '<p>PAGE</p>')
731
+        test_html_document = content_api.create(
732
+            content_type=ContentType.Page,
733
+            workspace=business_workspace,
734
+            parent=tool_folder,
735
+            label='test_html_page',
736
+            do_save=False,
737
+            do_notify=False,
738
+        )
739
+        content_api.update_content(test_html_document, 'test_html_page', '<p>HTML_DOCUMENT</p>')  # nopep8
740
+        dbsession.flush()
741
+        transaction.commit()
742
+        # test-itself
743
+        params = {
744
+            'parent_id': 1,
745
+            'show_archived': 1,
746
+            'show_deleted': 1,
747
+            'show_active': 1,
748
+            'content_type': 'html-documents',
749
+        }
750
+        self.testapp.authorization = (
751
+            'Basic',
752
+            (
753
+                'admin@admin.admin',
754
+                'admin@admin.admin'
755
+            )
756
+        )
757
+        res = self.testapp.get(
758
+            '/api/v2/workspaces/1/contents',
759
+            status=200,
760
+            params=params,
761
+        ).json_body
762
+        assert len(res) == 2
763
+        content = res[0]
764
+        assert content['content_type'] == 'html-documents'
765
+        assert content['content_id']
766
+        assert content['is_archived'] is False
767
+        assert content['is_deleted'] is False
768
+        assert content['label'] == 'test_page'
769
+        assert content['parent_id'] == 1
770
+        assert content['show_in_ui'] is True
771
+        assert content['slug'] == 'test-page'
772
+        assert content['status'] == 'open'
773
+        assert set(content['sub_content_types']) == {'thread', 'html-documents', 'folder', 'file'}  # nopep8
774
+        assert content['workspace_id'] == 1
775
+        content = res[1]
776
+        assert content['content_type'] == 'html-documents'
777
+        assert content['content_id']
778
+        assert content['is_archived'] is False
779
+        assert content['is_deleted'] is False
780
+        assert content['label'] == 'test_html_page'
781
+        assert content['parent_id'] == 1
782
+        assert content['show_in_ui'] is True
783
+        assert content['slug'] == 'test-html-page'
784
+        assert content['status'] == 'open'
785
+        assert set(content['sub_content_types']) == {'thread', 'html-documents', 'folder', 'file'}  # nopep8
786
+        assert content['workspace_id'] == 1
787
+        assert res[0]['content_id'] != res[1]['content_id']
542 788
 
543 789
     def test_api__get_workspace_content__ok_200__get_all_folder_content(self):
544 790
         """
@@ -549,6 +795,7 @@ class TestWorkspaceContents(FunctionalTest):
549 795
             'show_archived': 1,
550 796
             'show_deleted': 1,
551 797
             'show_active': 1,
798
+            'content_type': 'any'
552 799
         }
553 800
         self.testapp.authorization = (
554 801
             'Basic',

+ 5 - 0
tracim/views/core_api/schemas.py View File

@@ -164,6 +164,11 @@ class FilterContentQuerySchema(marshmallow.Schema):
164 164
                     'to allow to show only archived documents',
165 165
         validate=Range(min=0, max=1, error="Value must be 0 or 1"),
166 166
     )
167
+    content_type = marshmallow.fields.String(
168
+        example=ContentType.Any,
169
+        default=ContentType.Any,
170
+        validate=OneOf(ContentType.allowed_type_values())
171
+    )
167 172
 
168 173
     @post_load
169 174
     def make_content_filter(self, data):

+ 1 - 0
tracim/views/core_api/workspace_controller.py View File

@@ -109,6 +109,7 @@ class WorkspaceController(Controller):
109 109
         contents = api.get_all(
110 110
             parent_id=content_filter.parent_id,
111 111
             workspace=request.current_workspace,
112
+            content_type=content_filter.content_type,
112 113
         )
113 114
         contents = [
114 115
             api.get_content_in_context(content) for content in contents