Browse Source

disallow empty raw_content for comment and empty label for others contents + tests

Guénaël Muller 6 years ago
parent
commit
980b8f639b

+ 12 - 0
tracim/exceptions.py View File

131
 
131
 
132
 class WorkspacesDoNotMatch(TracimException):
132
 class WorkspacesDoNotMatch(TracimException):
133
     pass
133
     pass
134
+
135
+
136
+class EmptyValueNotAllowed(TracimException):
137
+    pass
138
+
139
+
140
+class EmptyLabelNotAllowed(EmptyValueNotAllowed):
141
+    pass
142
+
143
+
144
+class EmptyRawContentNotAllowed(EmptyValueNotAllowed):
145
+    pass

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

5
 import re
5
 import re
6
 import typing
6
 import typing
7
 from operator import itemgetter
7
 from operator import itemgetter
8
-from operator import not_
9
 
8
 
10
 import transaction
9
 import transaction
11
 from sqlalchemy import func
10
 from sqlalchemy import func
25
 
24
 
26
 from tracim.lib.utils.utils import cmp_to_key
25
 from tracim.lib.utils.utils import cmp_to_key
27
 from tracim.lib.core.notifications import NotifierFactory
26
 from tracim.lib.core.notifications import NotifierFactory
28
-from tracim.exceptions import SameValueError
27
+from tracim.exceptions import SameValueError, EmptyRawContentNotAllowed
28
+from tracim.exceptions import EmptyLabelNotAllowed
29
 from tracim.exceptions import ContentNotFound
29
 from tracim.exceptions import ContentNotFound
30
 from tracim.exceptions import WorkspacesDoNotMatch
30
 from tracim.exceptions import WorkspacesDoNotMatch
31
 from tracim.lib.utils.utils import current_date_for_filename
31
 from tracim.lib.utils.utils import current_date_for_filename
393
 
393
 
394
         return result
394
         return result
395
 
395
 
396
-    def create(self, content_type: str, workspace: Workspace, parent: Content=None, label:str ='', do_save=False, is_temporary: bool=False, do_notify=True) -> Content:
396
+    def create(self, content_type: str, workspace: Workspace, parent: Content=None, label: str ='', filename: str = '', do_save=False, is_temporary: bool=False, do_notify=True) -> Content:
397
         assert content_type in ContentType.allowed_types()
397
         assert content_type in ContentType.allowed_types()
398
 
398
 
399
         if content_type == ContentType.Folder and not label:
399
         if content_type == ContentType.Folder and not label:
400
             label = self.generate_folder_label(workspace, parent)
400
             label = self.generate_folder_label(workspace, parent)
401
 
401
 
402
         content = Content()
402
         content = Content()
403
+        if label:
404
+            content.label = label
405
+        elif filename:
406
+            # TODO - G.M - 2018-07-04 - File_name setting automatically
407
+            # set label and file_extension
408
+            content.file_name = label
409
+        else:
410
+            raise EmptyLabelNotAllowed()
411
+
403
         content.owner = self._user
412
         content.owner = self._user
404
         content.parent = parent
413
         content.parent = parent
405
         content.workspace = workspace
414
         content.workspace = workspace
406
         content.type = content_type
415
         content.type = content_type
407
-        content.label = label
408
         content.is_temporary = is_temporary
416
         content.is_temporary = is_temporary
409
         content.revision_type = ActionDescription.CREATION
417
         content.revision_type = ActionDescription.CREATION
410
 
418
 
419
             self.save(content, ActionDescription.CREATION, do_notify=do_notify)
427
             self.save(content, ActionDescription.CREATION, do_notify=do_notify)
420
         return content
428
         return content
421
 
429
 
422
-
423
     def create_comment(self, workspace: Workspace=None, parent: Content=None, content:str ='', do_save=False) -> Content:
430
     def create_comment(self, workspace: Workspace=None, parent: Content=None, content:str ='', do_save=False) -> Content:
424
-        assert parent  and parent.type!=ContentType.Folder
431
+        assert parent and parent.type != ContentType.Folder
432
+        if not content:
433
+            raise EmptyRawContentNotAllowed()
425
         item = Content()
434
         item = Content()
426
         item.owner = self._user
435
         item.owner = self._user
427
         item.parent = parent
436
         item.parent = parent
972
             # TODO - G.M - 20-03-2018 - Fix internatization for webdav access.
981
             # TODO - G.M - 20-03-2018 - Fix internatization for webdav access.
973
             # Internatization disabled in libcontent for now.
982
             # Internatization disabled in libcontent for now.
974
             raise SameValueError('The content did not changed')
983
             raise SameValueError('The content did not changed')
984
+        if not new_label:
985
+            raise EmptyLabelNotAllowed()
975
         item.owner = self._user
986
         item.owner = self._user
976
         item.label = new_label
987
         item.label = new_label
977
         item.description = new_content if new_content else item.description # TODO: convert urls into links
988
         item.description = new_content if new_content else item.description # TODO: convert urls into links

+ 1 - 0
tracim/lib/webdav/utils.py View File

176
         is_temporary = self._file_name.startswith('.~') or self._file_name.startswith('~')
176
         is_temporary = self._file_name.startswith('.~') or self._file_name.startswith('~')
177
 
177
 
178
         file = self._api.create(
178
         file = self._api.create(
179
+            filename=self._file_name,
179
             content_type=ContentType.File,
180
             content_type=ContentType.File,
180
             workspace=self._workspace,
181
             workspace=self._workspace,
181
             parent=self._parent,
182
             parent=self._parent,

+ 19 - 0
tracim/tests/functional/test_comments.py View File

94
         assert len(res.json_body) == 4
94
         assert len(res.json_body) == 4
95
         assert comment == res.json_body[3]
95
         assert comment == res.json_body[3]
96
 
96
 
97
+    def test_api__post_content_comment__err_400__empty_raw_content(self) -> None:
98
+        """
99
+        Get alls comments of a content
100
+        """
101
+        self.testapp.authorization = (
102
+            'Basic',
103
+            (
104
+                'admin@admin.admin',
105
+                'admin@admin.admin'
106
+            )
107
+        )
108
+        params = {
109
+            'raw_content': ''
110
+        }
111
+        res = self.testapp.post_json(
112
+            '/api/v2/workspaces/2/contents/7/comments',
113
+            params=params,
114
+            status=400
115
+        )
97
     def test_api__delete_content_comment__ok_200__user_is_owner_and_workspace_manager(self) -> None:  # nopep8
116
     def test_api__delete_content_comment__ok_200__user_is_owner_and_workspace_manager(self) -> None:  # nopep8
98
         """
117
         """
99
         delete comment (user is workspace_manager and owner)
118
         delete comment (user is workspace_manager and owner)

+ 42 - 0
tracim/tests/functional/test_contents.py View File

192
             status=400
192
             status=400
193
         )
193
         )
194
 
194
 
195
+    def test_api__update_html_document__err_400__empty_label(self) -> None:  # nopep8
196
+        """
197
+        Update(put) one html document of a content
198
+        """
199
+        self.testapp.authorization = (
200
+            'Basic',
201
+            (
202
+                'admin@admin.admin',
203
+                'admin@admin.admin'
204
+            )
205
+        )
206
+        params = {
207
+            'label': '',
208
+            'raw_content': '<p> Le nouveau contenu </p>',
209
+        }
210
+        res = self.testapp.put_json(
211
+            '/api/v2/workspaces/2/html-documents/6',
212
+            params=params,
213
+            status=400
214
+        )
215
+
195
     def test_api__update_html_document__ok_200__nominal_case(self) -> None:
216
     def test_api__update_html_document__ok_200__nominal_case(self) -> None:
196
         """
217
         """
197
         Update(put) one html document of a content
218
         Update(put) one html document of a content
603
         assert content['last_modifier'] == content['author']
624
         assert content['last_modifier'] == content['author']
604
         assert content['raw_content'] == '<p> Le nouveau contenu </p>'
625
         assert content['raw_content'] == '<p> Le nouveau contenu </p>'
605
 
626
 
627
+    def test_api__update_thread__err_400__empty_label(self) -> None:
628
+        """
629
+        Update(put) thread
630
+        """
631
+        self.testapp.authorization = (
632
+            'Basic',
633
+            (
634
+                'admin@admin.admin',
635
+                'admin@admin.admin'
636
+            )
637
+        )
638
+        params = {
639
+            'label': '',
640
+            'raw_content': '<p> Le nouveau contenu </p>',
641
+        }
642
+        res = self.testapp.put_json(
643
+            '/api/v2/workspaces/2/threads/7',
644
+            params=params,
645
+            status=400
646
+        )
647
+
606
     def test_api__get_thread_revisions__ok_200__nominal_case(
648
     def test_api__get_thread_revisions__ok_200__nominal_case(
607
             self
649
             self
608
     ) -> None:
650
     ) -> None:

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

834
         active_contents = self.testapp.get('/api/v2/workspaces/1/contents', params=params_active, status=200).json_body  # nopep8
834
         active_contents = self.testapp.get('/api/v2/workspaces/1/contents', params=params_active, status=200).json_body  # nopep8
835
         assert res.json_body in active_contents
835
         assert res.json_body in active_contents
836
 
836
 
837
+    def test_api__post_content_create_generic_content__err_400__empty_label(self) -> None:  # nopep8
838
+        """
839
+        Create generic content
840
+        """
841
+        self.testapp.authorization = (
842
+            'Basic',
843
+            (
844
+                'admin@admin.admin',
845
+                'admin@admin.admin'
846
+            )
847
+        )
848
+        params = {
849
+            'label': '',
850
+            'content_type': 'markdownpage',
851
+        }
852
+        res = self.testapp.post_json(
853
+            '/api/v2/workspaces/1/contents',
854
+            params=params,
855
+            status=400
856
+        )
857
+
858
+    def test_api__post_content_create_generic_content__err_400__wrong_content_type(self) -> None:  # nopep8
859
+        """
860
+        Create generic content
861
+        """
862
+        self.testapp.authorization = (
863
+            'Basic',
864
+            (
865
+                'admin@admin.admin',
866
+                'admin@admin.admin'
867
+            )
868
+        )
869
+        params = {
870
+            'label': 'GenericCreatedContent',
871
+            'content_type': 'unexistent-content-type',
872
+        }
873
+        res = self.testapp.post_json(
874
+            '/api/v2/workspaces/1/contents',
875
+            params=params,
876
+            status=400,
877
+        )
878
+
837
     def test_api_put_move_content__ok_200__nominal_case(self):
879
     def test_api_put_move_content__ok_200__nominal_case(self):
838
         """
880
         """
839
         Move content
881
         Move content

+ 91 - 24
tracim/tests/library/test_content_api.py View File

128
             session=self.session,
128
             session=self.session,
129
             config=self.app_config,
129
             config=self.app_config,
130
         )
130
         )
131
-        item = api.create(ContentType.Folder, workspace, None,
132
-                          'not_deleted', True)
133
-        item2 = api.create(ContentType.Folder, workspace, None,
134
-                           'to_delete', True)
131
+        item = api.create(
132
+            content_type=ContentType.Folder,
133
+            workspace=workspace,
134
+            parent=None,
135
+            label='not_deleted',
136
+            do_save=True
137
+        )
138
+        item2 = api.create(
139
+            content_type=ContentType.Folder,
140
+            workspace=workspace,
141
+            parent=None,
142
+            label='to_delete',
143
+            do_save=True
144
+        )
135
         uid = user.user_id
145
         uid = user.user_id
136
         wid = workspace.workspace_id
146
         wid = workspace.workspace_id
137
         transaction.commit()
147
         transaction.commit()
229
             session=self.session,
239
             session=self.session,
230
             config=self.app_config,
240
             config=self.app_config,
231
         )
241
         )
232
-        item = api.create(ContentType.Folder, workspace, None,
233
-                          'not_archived', True)
234
-        item2 = api.create(ContentType.Folder, workspace, None,
235
-                           'to_archive', True)
242
+        item = api.create(
243
+            content_type=ContentType.Folder,
244
+            workspace=workspace,
245
+            parent=None,
246
+            label='not_archived',
247
+            do_save=True
248
+        )
249
+        item2 = api.create(
250
+            content_type=ContentType.Folder,
251
+            workspace=workspace,
252
+            parent=None,
253
+            label='to_archive',
254
+            do_save=True
255
+        )
236
         uid = user.user_id
256
         uid = user.user_id
237
         wid = workspace.workspace_id
257
         wid = workspace.workspace_id
238
         transaction.commit()
258
         transaction.commit()
337
             session=self.session,
357
             session=self.session,
338
             config=self.app_config,
358
             config=self.app_config,
339
         )
359
         )
340
-        item = api.create(ContentType.Folder, workspace, None,
341
-                          'thefolder', True)
342
-        item2 = api.create(ContentType.File, workspace, None, 'thefile', True)
360
+        item = api.create(
361
+            content_type=ContentType.Folder,
362
+            workspace=workspace,
363
+            parent=None,
364
+            label='thefolder',
365
+            do_save=True
366
+        )
367
+        item2 = api.create(
368
+            content_type=ContentType.File,
369
+            workspace=workspace,
370
+            parent=None,
371
+            label='thefile',
372
+            do_save=True
373
+        )
343
         uid = user.user_id
374
         uid = user.user_id
344
         wid = workspace.workspace_id
375
         wid = workspace.workspace_id
345
         transaction.commit()
376
         transaction.commit()
1248
             config=self.app_config,
1279
             config=self.app_config,
1249
         )
1280
         )
1250
 
1281
 
1251
-        p = api.create(ContentType.Page, workspace, None,
1252
-                       'this_is_a_page', True)
1282
+        p = api.create(
1283
+            content_type=ContentType.Page,
1284
+            workspace=workspace,
1285
+            parent=None,
1286
+            label='this_is_a_page',
1287
+            do_save=True
1288
+        )
1253
 
1289
 
1254
         u1id = user1.user_id
1290
         u1id = user1.user_id
1255
         u2id = user2.user_id
1291
         u2id = user2.user_id
1453
             session=self.session,
1489
             session=self.session,
1454
             config=self.app_config,
1490
             config=self.app_config,
1455
         )
1491
         )
1456
-        p = api.create(ContentType.File, workspace, None,
1457
-                       'this_is_a_page', True)
1492
+        p = api.create(
1493
+            content_type=ContentType.File,
1494
+            workspace=workspace,
1495
+            parent=None,
1496
+            label='this_is_a_page',
1497
+            do_save=True
1498
+        )
1458
 
1499
 
1459
         u1id = user1.user_id
1500
         u1id = user1.user_id
1460
         u2id = user2.user_id
1501
         u2id = user2.user_id
1666
             show_archived=True,
1707
             show_archived=True,
1667
             config=self.app_config,
1708
             config=self.app_config,
1668
         )
1709
         )
1669
-        p = api.create(ContentType.File, workspace, None,
1670
-                       'this_is_a_page', True)
1710
+        p = api.create(
1711
+            content_type=ContentType.File,
1712
+            workspace=workspace,
1713
+            parent=None,
1714
+            label='this_is_a_page',
1715
+            do_save=True
1716
+        )
1671
 
1717
 
1672
         u1id = user1.user_id
1718
         u1id = user1.user_id
1673
         u2id = user2.user_id
1719
         u2id = user2.user_id
1822
             config=self.app_config,
1868
             config=self.app_config,
1823
             show_deleted=True,
1869
             show_deleted=True,
1824
         )
1870
         )
1825
-        p = api.create(ContentType.File, workspace, None,
1826
-                       'this_is_a_page', True)
1871
+        p = api.create(
1872
+            content_type=ContentType.File,
1873
+            workspace=workspace,
1874
+            parent=None,
1875
+            label='this_is_a_page',
1876
+            do_save=True
1877
+        )
1827
 
1878
 
1828
         u1id = user1.user_id
1879
         u1id = user1.user_id
1829
         u2id = user2.user_id
1880
         u2id = user2.user_id
2065
             session=self.session,
2116
             session=self.session,
2066
             config=self.app_config,
2117
             config=self.app_config,
2067
         )
2118
         )
2068
-        a = api.create(ContentType.Folder, workspace, None,
2069
-                       'this is randomized folder', True)
2070
-        p1 = api.create(ContentType.Page, workspace, a,
2071
-                        'this is dummy label content', True)
2072
-        p2 = api.create(ContentType.Page, workspace, a, 'Hey ! Jon !', True)
2119
+        a = api.create(
2120
+            content_type=ContentType.Folder,
2121
+            workspace=workspace,
2122
+            parent=None,
2123
+            label='this is randomized folder',
2124
+            do_save=True
2125
+        )
2126
+        p1 = api.create(
2127
+            content_type=ContentType.Page,
2128
+            workspace=workspace,
2129
+            parent=a,
2130
+            label='this is dummy label content',
2131
+            do_save=True
2132
+        )
2133
+        p2 = api.create(
2134
+            content_type=ContentType.Page,
2135
+            workspace=workspace,
2136
+            parent=a,
2137
+            label='Hey ! Jon !',
2138
+            do_save=True
2139
+        )
2073
 
2140
 
2074
         with new_revision(
2141
         with new_revision(
2075
             session=self.session,
2142
             session=self.session,

+ 1 - 0
tracim/tests/library/test_webdav.py View File

95
                        self.session,
95
                        self.session,
96
                        self.app_config
96
                        self.app_config
97
                        ).get_one_by_email(email)
97
                        ).get_one_by_email(email)
98
+
98
     def _put_new_text_file(
99
     def _put_new_text_file(
99
             self,
100
             self,
100
             provider,
101
             provider,

+ 2 - 1
tracim/views/contents_api/comment_controller.py View File

19
 from tracim.views.core_api.schemas import SetCommentSchema
19
 from tracim.views.core_api.schemas import SetCommentSchema
20
 from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
20
 from tracim.views.core_api.schemas import WorkspaceAndContentIdPathSchema
21
 from tracim.views.core_api.schemas import NoContentSchema
21
 from tracim.views.core_api.schemas import NoContentSchema
22
-from tracim.exceptions import WorkspaceNotFound
22
+from tracim.exceptions import WorkspaceNotFound, EmptyRawContentNotAllowed
23
 from tracim.exceptions import InsufficientUserRoleInWorkspace
23
 from tracim.exceptions import InsufficientUserRoleInWorkspace
24
 from tracim.exceptions import NotAuthenticated
24
 from tracim.exceptions import NotAuthenticated
25
 from tracim.exceptions import AuthenticationFailed
25
 from tracim.exceptions import AuthenticationFailed
59
         ]
59
         ]
60
 
60
 
61
     @hapic.with_api_doc(tags=[COMMENT_ENDPOINTS_TAG])
61
     @hapic.with_api_doc(tags=[COMMENT_ENDPOINTS_TAG])
62
+    @hapic.handle_exception(EmptyRawContentNotAllowed, HTTPStatus.BAD_REQUEST)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
64
     @hapic.input_body(SetCommentSchema())
65
     @hapic.input_body(SetCommentSchema())

+ 2 - 5
tracim/views/contents_api/html_document_controller.py View File

23
 from tracim.views.core_api.schemas import NoContentSchema
23
 from tracim.views.core_api.schemas import NoContentSchema
24
 from tracim.lib.utils.authorization import require_content_types
24
 from tracim.lib.utils.authorization import require_content_types
25
 from tracim.lib.utils.authorization import require_workspace_role
25
 from tracim.lib.utils.authorization import require_workspace_role
26
-from tracim.exceptions import WorkspaceNotFound
27
-from tracim.exceptions import ContentTypeNotAllowed
28
-from tracim.exceptions import InsufficientUserRoleInWorkspace
29
-from tracim.exceptions import NotAuthenticated
30
-from tracim.exceptions import AuthenticationFailed
26
+from tracim.exceptions import EmptyLabelNotAllowed
31
 from tracim.models.context_models import ContentInContext
27
 from tracim.models.context_models import ContentInContext
32
 from tracim.models.context_models import RevisionInContext
28
 from tracim.models.context_models import RevisionInContext
33
 from tracim.models.contents import ContentTypeLegacy as ContentType
29
 from tracim.models.contents import ContentTypeLegacy as ContentType
61
         return api.get_content_in_context(content)
57
         return api.get_content_in_context(content)
62
 
58
 
63
     @hapic.with_api_doc(tags=[HTML_DOCUMENT_ENDPOINTS_TAG])
59
     @hapic.with_api_doc(tags=[HTML_DOCUMENT_ENDPOINTS_TAG])
60
+    @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
64
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
61
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
65
     @require_content_types([html_documents_type])
62
     @require_content_types([html_documents_type])
66
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
63
     @hapic.input_path(WorkspaceAndContentIdPathSchema())

+ 2 - 4
tracim/views/contents_api/threads_controller.py View File

22
 from tracim.views.core_api.schemas import NoContentSchema
22
 from tracim.views.core_api.schemas import NoContentSchema
23
 from tracim.lib.utils.authorization import require_content_types
23
 from tracim.lib.utils.authorization import require_content_types
24
 from tracim.lib.utils.authorization import require_workspace_role
24
 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
25
+from tracim.exceptions import EmptyLabelNotAllowed
29
 from tracim.models.context_models import ContentInContext
26
 from tracim.models.context_models import ContentInContext
30
 from tracim.models.context_models import RevisionInContext
27
 from tracim.models.context_models import RevisionInContext
31
 from tracim.models.contents import ContentTypeLegacy as ContentType
28
 from tracim.models.contents import ContentTypeLegacy as ContentType
59
         return api.get_content_in_context(content)
56
         return api.get_content_in_context(content)
60
 
57
 
61
     @hapic.with_api_doc(tags=[THREAD_ENDPOINTS_TAG])
58
     @hapic.with_api_doc(tags=[THREAD_ENDPOINTS_TAG])
59
+    @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
60
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
     @require_content_types([thread_type])
61
     @require_content_types([thread_type])
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
62
     @hapic.input_path(WorkspaceAndContentIdPathSchema())

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

459
 
459
 
460
 class ContentModifyAbstractSchema(marshmallow.Schema):
460
 class ContentModifyAbstractSchema(marshmallow.Schema):
461
     label = marshmallow.fields.String(
461
     label = marshmallow.fields.String(
462
+        required=True,
462
         example='contract for client XXX',
463
         example='contract for client XXX',
463
         description='New title of the content'
464
         description='New title of the content'
464
     )
465
     )

+ 5 - 6
tracim/views/core_api/workspace_controller.py View File

11
 from tracim.lib.core.workspace import WorkspaceApi
11
 from tracim.lib.core.workspace import WorkspaceApi
12
 from tracim.lib.core.content import ContentApi
12
 from tracim.lib.core.content import ContentApi
13
 from tracim.lib.core.userworkspace import RoleApi
13
 from tracim.lib.core.userworkspace import RoleApi
14
-from tracim.lib.utils.authorization import require_workspace_role, \
15
-    require_candidate_workspace_role
14
+from tracim.lib.utils.authorization import require_workspace_role
15
+from tracim.lib.utils.authorization import require_candidate_workspace_role
16
 from tracim.models.data import UserRoleInWorkspace
16
 from tracim.models.data import UserRoleInWorkspace
17
 from tracim.models.data import ActionDescription
17
 from tracim.models.data import ActionDescription
18
 from tracim.models.context_models import UserRoleWorkspaceInContext
18
 from tracim.models.context_models import UserRoleWorkspaceInContext
19
 from tracim.models.context_models import ContentInContext
19
 from tracim.models.context_models import ContentInContext
20
-from tracim.exceptions import NotAuthenticated, InsufficientUserRoleInWorkspace
21
-from tracim.exceptions import WorkspaceNotFoundInTracimRequest
20
+from tracim.exceptions import EmptyLabelNotAllowed
22
 from tracim.exceptions import WorkspacesDoNotMatch
21
 from tracim.exceptions import WorkspacesDoNotMatch
23
-from tracim.exceptions import WorkspaceNotFound
24
 from tracim.views.controllers import Controller
22
 from tracim.views.controllers import Controller
25
 from tracim.views.core_api.schemas import FilterContentQuerySchema
23
 from tracim.views.core_api.schemas import FilterContentQuerySchema
26
 from tracim.views.core_api.schemas import ContentMoveSchema
24
 from tracim.views.core_api.schemas import ContentMoveSchema
117
 
115
 
118
     @hapic.with_api_doc(tags=[WORKSPACE_ENDPOINTS_TAG])
116
     @hapic.with_api_doc(tags=[WORKSPACE_ENDPOINTS_TAG])
119
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
117
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
118
+    @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
120
     @hapic.input_path(WorkspaceIdPathSchema())
119
     @hapic.input_path(WorkspaceIdPathSchema())
121
     @hapic.input_body(ContentCreationSchema())
120
     @hapic.input_body(ContentCreationSchema())
122
     @hapic.output_body(ContentDigestSchema())
121
     @hapic.output_body(ContentDigestSchema())
125
             context,
124
             context,
126
             request: TracimRequest,
125
             request: TracimRequest,
127
             hapic_data=None,
126
             hapic_data=None,
128
-    ) -> typing.List[ContentInContext]:
127
+    ) -> ContentInContext:
129
         """
128
         """
130
         create a generic empty content
129
         create a generic empty content
131
         """
130
         """