Procházet zdrojové kódy

default endpoints for files

Guénaël Muller před 6 roky
rodič
revize
621b8b79bf

+ 5 - 0
tracim/__init__.py Zobrazit soubor

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
+
3
+
2
 try:  # Python 3.5+
4
 try:  # Python 3.5+
3
     from http import HTTPStatus
5
     from http import HTTPStatus
4
 except ImportError:
6
 except ImportError:
27
 from tracim.views.core_api.user_controller import UserController
29
 from tracim.views.core_api.user_controller import UserController
28
 from tracim.views.core_api.workspace_controller import WorkspaceController
30
 from tracim.views.core_api.workspace_controller import WorkspaceController
29
 from tracim.views.contents_api.comment_controller import CommentController
31
 from tracim.views.contents_api.comment_controller import CommentController
32
+from tracim.views.contents_api.file_controller import FileController
30
 from tracim.views.errors import ErrorSchema
33
 from tracim.views.errors import ErrorSchema
31
 from tracim.exceptions import NotAuthenticated
34
 from tracim.exceptions import NotAuthenticated
32
 from tracim.exceptions import InsufficientUserProfile
35
 from tracim.exceptions import InsufficientUserProfile
107
     comment_controller = CommentController()
110
     comment_controller = CommentController()
108
     html_document_controller = HTMLDocumentController()
111
     html_document_controller = HTMLDocumentController()
109
     thread_controller = ThreadController()
112
     thread_controller = ThreadController()
113
+    file_controller = FileController()
110
     configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
114
     configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
111
     configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
115
     configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
112
     configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
116
     configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
114
     configurator.include(comment_controller.bind, route_prefix=BASE_API_V2)
118
     configurator.include(comment_controller.bind, route_prefix=BASE_API_V2)
115
     configurator.include(html_document_controller.bind, route_prefix=BASE_API_V2)  # nopep8
119
     configurator.include(html_document_controller.bind, route_prefix=BASE_API_V2)  # nopep8
116
     configurator.include(thread_controller.bind, route_prefix=BASE_API_V2)
120
     configurator.include(thread_controller.bind, route_prefix=BASE_API_V2)
121
+    configurator.include(file_controller.bind, route_prefix=BASE_API_V2)
117
 
122
 
118
     hapic.add_documentation_view(
123
     hapic.add_documentation_view(
119
         '/api/v2/doc',
124
         '/api/v2/doc',

+ 515 - 0
tracim/tests/functional/test_contents.py Zobrazit soubor

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
+import transaction
3
+from depot.io.utils import FileIntent
4
+
5
+from tracim import models
6
+from tracim.lib.core.content import ContentApi
7
+from tracim.lib.core.workspace import WorkspaceApi
8
+from tracim.models.data import ContentType
9
+from tracim.models import get_tm_session
2
 from tracim.tests import FunctionalTest
10
 from tracim.tests import FunctionalTest
3
 from tracim.tests import set_html_document_slug_to_legacy
11
 from tracim.tests import set_html_document_slug_to_legacy
4
 from tracim.fixtures.content import Content as ContentFixtures
12
 from tracim.fixtures.content import Content as ContentFixtures
429
         )
437
         )
430
 
438
 
431
 
439
 
440
+class TestFiles(FunctionalTest):
441
+    """
442
+    Tests for /api/v2/workspaces/{workspace_id}/files/{content_id}
443
+    endpoint
444
+    """
445
+
446
+    fixtures = [BaseFixture, ContentFixtures]
447
+
448
+    def test_api__get_file__ok_200__nominal_case(self) -> None:
449
+        """
450
+        Get one file of a content
451
+        """
452
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
453
+        admin = dbsession.query(models.User) \
454
+            .filter(models.User.email == 'admin@admin.admin') \
455
+            .one()
456
+        workspace_api = WorkspaceApi(
457
+            current_user=admin,
458
+            session=dbsession,
459
+            config=self.app_config
460
+        )
461
+        content_api = ContentApi(
462
+            current_user=admin,
463
+            session=dbsession,
464
+            config=self.app_config
465
+        )
466
+        business_workspace = workspace_api.get_one(1)
467
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
468
+        test_file = content_api.create(
469
+            content_type=ContentType.File,
470
+            workspace=business_workspace,
471
+            parent=tool_folder,
472
+            label='Test file',
473
+            do_save=False,
474
+            do_notify=False,
475
+        )
476
+        test_file.file_extension = '.txt'
477
+        test_file.depot_file = FileIntent(
478
+            b'Test file',
479
+            'Test_file.txt',
480
+            'text/plain',
481
+        )
482
+        content_api.update_content(test_file, 'Test_file', '<p>description</p>')  # nopep8
483
+        dbsession.flush()
484
+        transaction.commit()
485
+
486
+        self.testapp.authorization = (
487
+            'Basic',
488
+            (
489
+                'admin@admin.admin',
490
+                'admin@admin.admin'
491
+            )
492
+        )
493
+        res = self.testapp.get(
494
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
495
+            status=200
496
+        )
497
+        content = res.json_body
498
+        assert content['content_type'] == 'file'
499
+        assert content['content_id'] == test_file.content_id
500
+        assert content['is_archived'] is False
501
+        assert content['is_deleted'] is False
502
+        assert content['label'] == 'Test_file'
503
+        assert content['parent_id'] == 1
504
+        assert content['show_in_ui'] is True
505
+        assert content['slug'] == 'test-file'
506
+        assert content['status'] == 'open'
507
+        assert content['workspace_id'] == 1
508
+        assert content['current_revision_id']
509
+        # TODO - G.M - 2018-06-173 - check date format
510
+        assert content['created']
511
+        assert content['author']
512
+        assert content['author']['user_id'] == 1
513
+        assert content['author']['avatar_url'] is None
514
+        assert content['author']['public_name'] == 'Global manager'
515
+        # TODO - G.M - 2018-06-173 - check date format
516
+        assert content['modified']
517
+        assert content['last_modifier'] == content['author']
518
+        assert content['raw_content'] == '<p>description</p>'  # nopep8
519
+
520
+    def test_api__get_files__err_400__wrong_content_type(self) -> None:
521
+        """
522
+        Get one file of a content content
523
+        """
524
+        self.testapp.authorization = (
525
+            'Basic',
526
+            (
527
+                'admin@admin.admin',
528
+                'admin@admin.admin'
529
+            )
530
+        )
531
+        res = self.testapp.get(
532
+            '/api/v2/workspaces/2/files/6',
533
+            status=400
534
+        )
535
+
536
+    def test_api__get_file__err_400__content_does_not_exist(self) -> None:  # nopep8
537
+        """
538
+        Get one file (content 170 does not exist in db
539
+        """
540
+        self.testapp.authorization = (
541
+            'Basic',
542
+            (
543
+                'admin@admin.admin',
544
+                'admin@admin.admin'
545
+            )
546
+        )
547
+        res = self.testapp.get(
548
+            '/api/v2/workspaces/1/files/170',
549
+            status=400
550
+        )
551
+
552
+    def test_api__get_file__err_400__content_not_in_workspace(self) -> None:  # nopep8
553
+        """
554
+        Get one file (content 9 is in workspace 2)
555
+        """
556
+        self.testapp.authorization = (
557
+            'Basic',
558
+            (
559
+                'admin@admin.admin',
560
+                'admin@admin.admin'
561
+            )
562
+        )
563
+        res = self.testapp.get(
564
+            '/api/v2/workspaces/1/files/9',
565
+            status=400
566
+        )
567
+
568
+    def test_api__get_file__err_400__workspace_does_not_exist(self) -> None:  # nopep8
569
+        """
570
+        Get one file (Workspace 40 does not exist)
571
+        """
572
+        self.testapp.authorization = (
573
+            'Basic',
574
+            (
575
+                'admin@admin.admin',
576
+                'admin@admin.admin'
577
+            )
578
+        )
579
+        res = self.testapp.get(
580
+            '/api/v2/workspaces/40/files/9',
581
+            status=400
582
+        )
583
+
584
+    def test_api__get_file__err_400__workspace_id_is_not_int(self) -> None:  # nopep8
585
+        """
586
+        Get one file, workspace id is not int
587
+        """
588
+        self.testapp.authorization = (
589
+            'Basic',
590
+            (
591
+                'admin@admin.admin',
592
+                'admin@admin.admin'
593
+            )
594
+        )
595
+        res = self.testapp.get(
596
+            '/api/v2/workspaces/coucou/files/9',
597
+            status=400
598
+        )
599
+
600
+    def test_api__get_file__err_400__content_id_is_not_int(self) -> None:  # nopep8
601
+        """
602
+        Get one file, content_id is not int
603
+        """
604
+        self.testapp.authorization = (
605
+            'Basic',
606
+            (
607
+                'admin@admin.admin',
608
+                'admin@admin.admin'
609
+            )
610
+        )
611
+        res = self.testapp.get(
612
+            '/api/v2/workspaces/2/files/coucou',
613
+            status=400
614
+        )
615
+
616
+    def test_api__update_file_info_err_400__empty_label(self) -> None:  # nopep8
617
+        """
618
+        Update(put) one file
619
+        """
620
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
621
+        admin = dbsession.query(models.User) \
622
+            .filter(models.User.email == 'admin@admin.admin') \
623
+            .one()
624
+        workspace_api = WorkspaceApi(
625
+            current_user=admin,
626
+            session=dbsession,
627
+            config=self.app_config
628
+        )
629
+        content_api = ContentApi(
630
+            current_user=admin,
631
+            session=dbsession,
632
+            config=self.app_config
633
+        )
634
+        business_workspace = workspace_api.get_one(1)
635
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
636
+        test_file = content_api.create(
637
+            content_type=ContentType.File,
638
+            workspace=business_workspace,
639
+            parent=tool_folder,
640
+            label='Test file',
641
+            do_save=False,
642
+            do_notify=False,
643
+        )
644
+        test_file.file_extension = '.txt'
645
+        test_file.depot_file = FileIntent(
646
+            b'Test file',
647
+            'Test_file.txt',
648
+            'text/plain',
649
+        )
650
+        content_api.update_content(test_file, 'Test_file', '<p>description</p>')  # nopep8
651
+        dbsession.flush()
652
+        transaction.commit()
653
+
654
+        self.testapp.authorization = (
655
+            'Basic',
656
+            (
657
+                'admin@admin.admin',
658
+                'admin@admin.admin'
659
+            )
660
+        )
661
+        params = {
662
+            'label': '',
663
+            'raw_content': '<p> Le nouveau contenu </p>',
664
+        }
665
+        res = self.testapp.put_json(
666
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
667
+            params=params,
668
+            status=400
669
+        )
670
+
671
+    def test_api__update_file_info__ok_200__nominal_case(self) -> None:
672
+        """
673
+        Update(put) one file
674
+        """
675
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
676
+        admin = dbsession.query(models.User) \
677
+            .filter(models.User.email == 'admin@admin.admin') \
678
+            .one()
679
+        workspace_api = WorkspaceApi(
680
+            current_user=admin,
681
+            session=dbsession,
682
+            config=self.app_config
683
+        )
684
+        content_api = ContentApi(
685
+            current_user=admin,
686
+            session=dbsession,
687
+            config=self.app_config
688
+        )
689
+        business_workspace = workspace_api.get_one(1)
690
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
691
+        test_file = content_api.create(
692
+            content_type=ContentType.File,
693
+            workspace=business_workspace,
694
+            parent=tool_folder,
695
+            label='Test file',
696
+            do_save=False,
697
+            do_notify=False,
698
+        )
699
+        test_file.file_extension = '.txt'
700
+        test_file.depot_file = FileIntent(
701
+            b'Test file',
702
+            'Test_file.txt',
703
+            'text/plain',
704
+        )
705
+        content_api.update_content(test_file, 'Test_file', '<p>description</p>')  # nopep8
706
+        dbsession.flush()
707
+        transaction.commit()
708
+
709
+        self.testapp.authorization = (
710
+            'Basic',
711
+            (
712
+                'admin@admin.admin',
713
+                'admin@admin.admin'
714
+            )
715
+        )
716
+        params = {
717
+            'label': 'My New label',
718
+            'raw_content': '<p> Le nouveau contenu </p>',
719
+        }
720
+        res = self.testapp.put_json(
721
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
722
+            params=params,
723
+            status=200
724
+        )
725
+        content = res.json_body
726
+        assert content['content_type'] == 'file'
727
+        assert content['content_id'] == test_file.content_id
728
+        assert content['is_archived'] is False
729
+        assert content['is_deleted'] is False
730
+        assert content['label'] == 'My New label'
731
+        assert content['parent_id'] == 1
732
+        assert content['show_in_ui'] is True
733
+        assert content['slug'] == 'my-new-label'
734
+        assert content['status'] == 'open'
735
+        assert content['workspace_id'] == 1
736
+        assert content['current_revision_id']
737
+        # TODO - G.M - 2018-06-173 - check date format
738
+        assert content['created']
739
+        assert content['author']
740
+        assert content['author']['user_id'] == 1
741
+        assert content['author']['avatar_url'] is None
742
+        assert content['author']['public_name'] == 'Global manager'
743
+        # TODO - G.M - 2018-06-173 - check date format
744
+        assert content['modified']
745
+        assert content['last_modifier'] == content['author']
746
+        assert content['raw_content'] == '<p> Le nouveau contenu </p>'
747
+
748
+        res = self.testapp.get(
749
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
750
+            status=200
751
+        )
752
+        content = res.json_body
753
+        assert content['content_type'] == 'file'
754
+        assert content['content_id'] == test_file.content_id
755
+        assert content['is_archived'] is False
756
+        assert content['is_deleted'] is False
757
+        assert content['label'] == 'My New label'
758
+        assert content['parent_id'] == 1
759
+        assert content['show_in_ui'] is True
760
+        assert content['slug'] == 'my-new-label'
761
+        assert content['status'] == 'open'
762
+        assert content['workspace_id'] == 1
763
+        assert content['current_revision_id']
764
+        # TODO - G.M - 2018-06-173 - check date format
765
+        assert content['created']
766
+        assert content['author']
767
+        assert content['author']['user_id'] == 1
768
+        assert content['author']['avatar_url'] is None
769
+        assert content['author']['public_name'] == 'Global manager'
770
+        # TODO - G.M - 2018-06-173 - check date format
771
+        assert content['modified']
772
+        assert content['last_modifier'] == content['author']
773
+        assert content['raw_content'] == '<p> Le nouveau contenu </p>'
774
+
775
+    def test_api__get_file_revisions__ok_200__nominal_case(
776
+            self
777
+    ) -> None:
778
+        """
779
+        Get file revisions
780
+        """
781
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
782
+        admin = dbsession.query(models.User) \
783
+            .filter(models.User.email == 'admin@admin.admin') \
784
+            .one()
785
+        workspace_api = WorkspaceApi(
786
+            current_user=admin,
787
+            session=dbsession,
788
+            config=self.app_config
789
+        )
790
+        content_api = ContentApi(
791
+            current_user=admin,
792
+            session=dbsession,
793
+            config=self.app_config
794
+        )
795
+        business_workspace = workspace_api.get_one(1)
796
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
797
+        test_file = content_api.create(
798
+            content_type=ContentType.File,
799
+            workspace=business_workspace,
800
+            parent=tool_folder,
801
+            label='Test file',
802
+            do_save=False,
803
+            do_notify=False,
804
+        )
805
+        test_file.file_extension = '.txt'
806
+        test_file.depot_file = FileIntent(
807
+            b'Test file',
808
+            'Test_file.txt',
809
+            'text/plain',
810
+        )
811
+        content_api.update_content(test_file, 'Test_file', '<p>description</p>')  # nopep8
812
+        dbsession.flush()
813
+        transaction.commit()
814
+
815
+        self.testapp.authorization = (
816
+            'Basic',
817
+            (
818
+                'admin@admin.admin',
819
+                'admin@admin.admin'
820
+            )
821
+        )
822
+        res = self.testapp.get(
823
+            '/api/v2/workspaces/1/files/{}/revisions'.format(test_file.content_id),
824
+            status=200
825
+        )
826
+        revisions = res.json_body
827
+        assert len(revisions) == 1
828
+        revision = revisions[0]
829
+        assert revision['content_type'] == 'file'
830
+        assert revision['content_id'] == test_file.content_id
831
+        assert revision['is_archived'] is False
832
+        assert revision['is_deleted'] is False
833
+        assert revision['label'] == 'Test_file'
834
+        assert revision['parent_id'] == 1
835
+        assert revision['show_in_ui'] is True
836
+        assert revision['slug'] == 'test-file'
837
+        assert revision['status'] == 'open'
838
+        assert revision['workspace_id'] == 1
839
+        assert revision['revision_id']
840
+        assert revision['sub_content_types']
841
+        # TODO - G.M - 2018-06-173 - Test with real comments
842
+        assert revision['comment_ids'] == []
843
+        # TODO - G.M - 2018-06-173 - check date format
844
+        assert revision['created']
845
+        assert revision['author']
846
+        assert revision['author']['user_id'] == 1
847
+        assert revision['author']['avatar_url'] is None
848
+        assert revision['author']['public_name'] == 'Global manager'
849
+
850
+    def test_api__set_file_status__ok_200__nominal_case(self) -> None:
851
+        """
852
+        set file status
853
+        """
854
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
855
+        admin = dbsession.query(models.User) \
856
+            .filter(models.User.email == 'admin@admin.admin') \
857
+            .one()
858
+        workspace_api = WorkspaceApi(
859
+            current_user=admin,
860
+            session=dbsession,
861
+            config=self.app_config
862
+        )
863
+        content_api = ContentApi(
864
+            current_user=admin,
865
+            session=dbsession,
866
+            config=self.app_config
867
+        )
868
+        business_workspace = workspace_api.get_one(1)
869
+        tool_folder = content_api.get_one(1, content_type=ContentType.Any)
870
+        test_file = content_api.create(
871
+            content_type=ContentType.File,
872
+            workspace=business_workspace,
873
+            parent=tool_folder,
874
+            label='Test file',
875
+            do_save=False,
876
+            do_notify=False,
877
+        )
878
+        test_file.file_extension = '.txt'
879
+        test_file.depot_file = FileIntent(
880
+            b'Test file',
881
+            'Test_file.txt',
882
+            'text/plain',
883
+        )
884
+        content_api.update_content(test_file, 'Test_file', '<p>description</p>')  # nopep8
885
+        dbsession.flush()
886
+        transaction.commit()
887
+
888
+        self.testapp.authorization = (
889
+            'Basic',
890
+            (
891
+                'admin@admin.admin',
892
+                'admin@admin.admin'
893
+            )
894
+        )
895
+        params = {
896
+            'status': 'closed-deprecated',
897
+        }
898
+
899
+        # before
900
+        res = self.testapp.get(
901
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
902
+            status=200
903
+        )
904
+        content = res.json_body
905
+        assert content['content_type'] == 'file'
906
+        assert content['content_id'] == test_file.content_id
907
+        assert content['status'] == 'open'
908
+
909
+        # set status
910
+        res = self.testapp.put_json(
911
+            '/api/v2/workspaces/1/files/{}/status'.format(test_file.content_id),
912
+            params=params,
913
+            status=204
914
+        )
915
+
916
+        # after
917
+        res = self.testapp.get(
918
+            '/api/v2/workspaces/1/files/{}'.format(test_file.content_id),
919
+            status=200
920
+        )
921
+        content = res.json_body
922
+        assert content['content_type'] == 'file'
923
+        assert content['content_id'] == test_file.content_id
924
+        assert content['status'] == 'closed-deprecated'
925
+
926
+    def test_api__set_file_status__err_400__wrong_status(self) -> None:
927
+        """
928
+        set file status
929
+        """
930
+        self.testapp.authorization = (
931
+            'Basic',
932
+            (
933
+                'admin@admin.admin',
934
+                'admin@admin.admin'
935
+            )
936
+        )
937
+        params = {
938
+            'status': 'unexistant-status',
939
+        }
940
+        res = self.testapp.put_json(
941
+            '/api/v2/workspaces/2/files/6/status',
942
+            params=params,
943
+            status=400
944
+        )
945
+
946
+
432
 class TestThreads(FunctionalTest):
947
 class TestThreads(FunctionalTest):
433
     """
948
     """
434
     Tests for /api/v2/workspaces/{workspace_id}/threads/{content_id}
949
     Tests for /api/v2/workspaces/{workspace_id}/threads/{content_id}

+ 81 - 30
tracim/views/contents_api/file_controller.py Zobrazit soubor

3
 
3
 
4
 import transaction
4
 import transaction
5
 from pyramid.config import Configurator
5
 from pyramid.config import Configurator
6
+
7
+from tracim.exceptions import EmptyLabelNotAllowed
6
 from tracim.models.data import UserRoleInWorkspace
8
 from tracim.models.data import UserRoleInWorkspace
7
 
9
 
8
 try:  # Python 3.5+
10
 try:  # Python 3.5+
17
 from tracim.views.core_api.schemas import FileContentSchema
19
 from tracim.views.core_api.schemas import FileContentSchema
18
 from tracim.views.core_api.schemas import FileRevisionSchema
20
 from tracim.views.core_api.schemas import FileRevisionSchema
19
 from tracim.views.core_api.schemas import SetContentStatusSchema
21
 from tracim.views.core_api.schemas import SetContentStatusSchema
20
-from tracim.views.core_api.schemas import FileModifySchema
22
+from tracim.views.core_api.schemas import FileContentModifySchema
21
 from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
23
 from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
22
 from tracim.views.core_api.schemas import NoContentSchema
24
 from tracim.views.core_api.schemas import NoContentSchema
23
 from tracim.lib.utils.authorization import require_content_types
25
 from tracim.lib.utils.authorization import require_content_types
24
 from tracim.lib.utils.authorization import require_workspace_role
26
 from tracim.lib.utils.authorization import require_workspace_role
25
-from tracim.exceptions import WorkspaceNotFound, ContentTypeNotAllowed
26
-from tracim.exceptions import InsufficientUserRoleInWorkspace
27
-from tracim.exceptions import NotAuthenticated
28
-from tracim.exceptions import AuthenticationFailed
29
 from tracim.models.context_models import ContentInContext
27
 from tracim.models.context_models import ContentInContext
30
 from tracim.models.context_models import RevisionInContext
28
 from tracim.models.context_models import RevisionInContext
31
 from tracim.models.contents import ContentTypeLegacy as ContentType
29
 from tracim.models.contents import ContentTypeLegacy as ContentType
37
 
35
 
38
 class FileController(Controller):
36
 class FileController(Controller):
39
 
37
 
38
+    # # File data
39
+    # @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
40
+    # @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
41
+    # @require_content_types([file_type])
42
+    # @hapic.input_path(WorkspaceAndContentIdPathSchema())
43
+    # #@hapic.input_files()
44
+    # @hapic.output_file([])
45
+    # def upload_file(self, context, request: TracimRequest, hapic_data=None):
46
+    #     # TODO - G.M - 2018-07-05 - Do this endpoint
47
+    #     app_config = request.registry.settings['CFG']
48
+    #     api = ContentApi(
49
+    #         current_user=request.current_user,
50
+    #         session=request.dbsession,
51
+    #         config=app_config,
52
+    #     )
53
+    #     content = api.get_one(
54
+    #         hapic_data.path.content_id,
55
+    #         content_type=ContentType.Any
56
+    #     )
57
+    #     file = request.POST['files']
58
+    #     api.update_file_data(
59
+    #         content,
60
+    #         new_filename=file.filename,
61
+    #         new_mimetype=file.type,
62
+    #         new_content=file.file,
63
+    #     )
64
+    #     return content.depot_file
65
+    #
66
+    # @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
67
+    # @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
68
+    # @require_content_types([file_type])
69
+    # @hapic.input_path(WorkspaceAndContentIdPathSchema())
70
+    # @hapic.output_file([])
71
+    # def download_file(self, context, request: TracimRequest, hapic_data=None):
72
+    #     # TODO - G.M - 2018-07-05 - Do this endpoint
73
+    #     app_config = request.registry.settings['CFG']
74
+    #     api = ContentApi(
75
+    #         current_user=request.current_user,
76
+    #         session=request.dbsession,
77
+    #         config=app_config,
78
+    #     )
79
+    #     content = api.get_one(
80
+    #         hapic_data.path.content_id,
81
+    #         content_type=ContentType.Any
82
+    #     )
83
+    #     return content.depot_file
84
+
85
+    # Previews
86
+    # def get_file_preview(self):
87
+    #     # TODO - G.M - 2018-07-05 - Do this endpoint
88
+    #     pass
89
+    
90
+    # File infos
40
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
91
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
41
-    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
42
-    @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
43
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
44
-    @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
45
-    @hapic.handle_exception(ContentTypeNotAllowed, HTTPStatus.BAD_REQUEST)
46
     @require_workspace_role(UserRoleInWorkspace.READER)
92
     @require_workspace_role(UserRoleInWorkspace.READER)
47
     @require_content_types([file_type])
93
     @require_content_types([file_type])
48
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
94
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
49
     @hapic.output_body(FileContentSchema())
95
     @hapic.output_body(FileContentSchema())
50
-    def get_file(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
96
+    def get_file_infos(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
51
         """
97
         """
52
         Get thread content
98
         Get thread content
53
         """
99
         """
64
         return api.get_content_in_context(content)
110
         return api.get_content_in_context(content)
65
 
111
 
66
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
112
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
67
-    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
68
-    @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
69
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
70
-    @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
113
+    @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
71
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
114
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
72
     @require_content_types([file_type])
115
     @require_content_types([file_type])
73
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
116
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
74
-    @hapic.input_body(FileModifySchema())
117
+    @hapic.input_body(FileContentModifySchema())
75
     @hapic.output_body(FileContentSchema())
118
     @hapic.output_body(FileContentSchema())
76
-    def update_file(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
119
+    def update_file_info(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
77
         """
120
         """
78
         update thread
121
         update thread
79
         """
122
         """
102
         return api.get_content_in_context(content)
145
         return api.get_content_in_context(content)
103
 
146
 
104
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
147
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
105
-    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
106
-    @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
107
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
108
-    @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
109
     @require_workspace_role(UserRoleInWorkspace.READER)
148
     @require_workspace_role(UserRoleInWorkspace.READER)
110
     @require_content_types([file_type])
149
     @require_content_types([file_type])
111
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
150
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
136
         ]
175
         ]
137
 
176
 
138
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
177
     @hapic.with_api_doc(tags=[FILE_ENDPOINTS_TAG])
139
-    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
140
-    @hapic.handle_exception(InsufficientUserRoleInWorkspace, HTTPStatus.FORBIDDEN)
141
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
142
-    @hapic.handle_exception(AuthenticationFailed, HTTPStatus.FORBIDDEN)
178
+    @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
143
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
179
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
144
     @require_content_types([file_type])
180
     @require_content_types([file_type])
145
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
181
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
172
         return
208
         return
173
 
209
 
174
     def bind(self, configurator: Configurator) -> None:
210
     def bind(self, configurator: Configurator) -> None:
175
-        # Get file
211
+        # Get file info
176
         configurator.add_route(
212
         configurator.add_route(
177
-            'file',
213
+            'file_info',
178
             '/workspaces/{workspace_id}/files/{content_id}',
214
             '/workspaces/{workspace_id}/files/{content_id}',
179
             request_method='GET'
215
             request_method='GET'
180
         )
216
         )
181
-        configurator.add_view(self.get_file, route_name='file')  # nopep8
217
+        configurator.add_view(self.get_file_infos, route_name='file_info')  # nopep8
182
 
218
 
183
         # update file
219
         # update file
184
         configurator.add_route(
220
         configurator.add_route(
185
-            'update_file',
221
+            'update_file_info',
186
             '/workspaces/{workspace_id}/files/{content_id}',
222
             '/workspaces/{workspace_id}/files/{content_id}',
187
             request_method='PUT'
223
             request_method='PUT'
188
         )  # nopep8
224
         )  # nopep8
189
-        configurator.add_view(self.update_file, route_name='update_file')  # nopep8
225
+        configurator.add_view(self.update_file_info, route_name='update_file_info')  # nopep8
190
 
226
 
227
+        # # upload new file data
228
+        # configurator.add_route(
229
+        #     'upload_file',
230
+        #     '/workspaces/{workspace_id}/files/{content_id}/file_data',  # nopep8
231
+        #     request_method='PUT'
232
+        # )
233
+        # configurator.add_view(self.upload_file, route_name='upload_file')  # nopep8
234
+        #
235
+        # # download file data
236
+        # configurator.add_route(
237
+        #     'download_file',
238
+        #     '/workspaces/{workspace_id}/files/{content_id}/file_data',  # nopep8
239
+        #     request_method='GET'
240
+        # )
241
+        # configurator.add_view(self.download_file, route_name='download_file')  # nopep8
191
         # get file revisions
242
         # get file revisions
192
         configurator.add_route(
243
         configurator.add_route(
193
             'file_revisions',
244
             'file_revisions',

+ 17 - 0
tracim/views/core_api/schemas.py Zobrazit soubor

411
     )
411
     )
412
 
412
 
413
 
413
 
414
+class FileInfoAbstractSchema(marshmallow.Schema):
415
+    raw_content = marshmallow.fields.String(
416
+        description='raw text or html description of the file'
417
+    )
418
+
419
+
414
 class TextBasedContentSchema(ContentSchema, TextBasedDataAbstractSchema):
420
 class TextBasedContentSchema(ContentSchema, TextBasedDataAbstractSchema):
415
     pass
421
     pass
416
 
422
 
417
 
423
 
424
+class FileContentSchema(ContentSchema, FileInfoAbstractSchema):
425
+    pass
426
+
418
 #####
427
 #####
419
 # Revision
428
 # Revision
420
 #####
429
 #####
434
     pass
443
     pass
435
 
444
 
436
 
445
 
446
+class FileRevisionSchema(RevisionSchema, FileInfoAbstractSchema):
447
+    pass
448
+
449
+
437
 class CommentSchema(marshmallow.Schema):
450
 class CommentSchema(marshmallow.Schema):
438
     content_id = marshmallow.fields.Int(example=6)
451
     content_id = marshmallow.fields.Int(example=6)
439
     parent_id = marshmallow.fields.Int(example=34)
452
     parent_id = marshmallow.fields.Int(example=34)
472
         return TextBasedContentUpdate(**data)
485
         return TextBasedContentUpdate(**data)
473
 
486
 
474
 
487
 
488
+class FileContentModifySchema(TextBasedContentModifySchema):
489
+    pass
490
+
491
+
475
 class SetContentStatusSchema(marshmallow.Schema):
492
 class SetContentStatusSchema(marshmallow.Schema):
476
     status = marshmallow.fields.Str(
493
     status = marshmallow.fields.Str(
477
         example='closed-deprecated',
494
         example='closed-deprecated',