Procházet zdrojové kódy

Merge pull request #16 from tracim/feature/638_refactor_applications+support_for_color.json

Bastien Sevajol před 6 roky
rodič
revize
320149c8e9
No account linked to committer's email
55 změnil soubory, kde provedl 748 přidání a 496 odebrání
  1. 2 0
      .gitignore
  2. 4 1
      backend/README.md
  3. 6 0
      backend/color-test.json
  4. 9 0
      backend/development.ini.sample
  5. 0 1
      backend/setup.py
  6. 19 0
      backend/tests_configs.ini
  7. 76 0
      backend/tracim_backend/app_models/applications.py
  8. 53 86
      backend/tracim_backend/app_models/contents.py
  9. 11 0
      backend/tracim_backend/app_models/validator.py
  10. 33 0
      backend/tracim_backend/app_models/workspace_menu_entries.py
  11. 149 4
      backend/tracim_backend/config.py
  12. 6 0
      backend/tracim_backend/exceptions.py
  13. 11 0
      backend/tracim_backend/extensions.py
  14. 1 1
      backend/tracim_backend/fixtures/content.py
  15. 70 0
      backend/tracim_backend/lib/core/application.py
  16. 4 4
      backend/tracim_backend/lib/core/content.py
  17. 1 1
      backend/tracim_backend/lib/mail_notifier/notifier.py
  18. 1 1
      backend/tracim_backend/lib/utils/authentification.py
  19. 5 7
      backend/tracim_backend/lib/utils/authorization.py
  20. 1 1
      backend/tracim_backend/lib/utils/request.py
  21. 67 6
      backend/tracim_backend/lib/utils/utils.py
  22. 1 1
      backend/tracim_backend/lib/webdav/dav_provider.py
  23. 1 1
      backend/tracim_backend/lib/webdav/design.py
  24. 1 1
      backend/tracim_backend/lib/webdav/resources.py
  25. 1 1
      backend/tracim_backend/lib/webdav/utils.py
  26. 1 1
      backend/tracim_backend/models/__init__.py
  27. 0 117
      backend/tracim_backend/models/applications.py
  28. 8 4
      backend/tracim_backend/models/context_models.py
  29. 5 5
      backend/tracim_backend/models/data.py
  30. 0 71
      backend/tracim_backend/models/workspace_menu_entries.py
  31. 1 1
      backend/tracim_backend/tests/__init__.py
  32. 1 1
      backend/tracim_backend/tests/functional/test_contents.py
  33. 1 1
      backend/tracim_backend/tests/functional/test_mail_notification.py
  34. 10 2
      backend/tracim_backend/tests/functional/test_system.py
  35. 26 39
      backend/tracim_backend/tests/functional/test_user.py
  36. 46 42
      backend/tracim_backend/tests/functional/test_workspaces.py
  37. 1 1
      backend/tracim_backend/tests/library/test_content_api.py
  38. 3 10
      backend/tracim_backend/tests/library/test_webdav.py
  39. 1 1
      backend/tracim_backend/tests/models/test_content.py
  40. 1 1
      backend/tracim_backend/tests/models/test_content_revision.py
  41. 2 2
      backend/tracim_backend/views/contents_api/comment_controller.py
  42. 17 17
      backend/tracim_backend/views/contents_api/file_controller.py
  43. 6 6
      backend/tracim_backend/views/contents_api/folder_controller.py
  44. 7 7
      backend/tracim_backend/views/contents_api/html_document_controller.py
  45. 7 7
      backend/tracim_backend/views/contents_api/threads_controller.py
  46. 12 10
      backend/tracim_backend/views/core_api/schemas.py
  47. 1 1
      backend/tracim_backend/views/core_api/session_controller.py
  48. 9 4
      backend/tracim_backend/views/core_api/system_controller.py
  49. 2 2
      backend/tracim_backend/views/core_api/user_controller.py
  50. 2 2
      backend/tracim_backend/views/core_api/workspace_controller.py
  51. 9 3
      backend/tracim_backend/views/frontend.py
  52. 10 0
      backend/wsgidav-test.conf
  53. 5 0
      backend_lib.sh
  54. 3 3
      color.json.sample
  55. 18 18
      frontend/dist/index.mak

+ 2 - 0
.gitignore Zobrazit soubor

6
 frontend_lib/dist/tracim_frontend_lib.js
6
 frontend_lib/dist/tracim_frontend_lib.js
7
 npm-debug.log
7
 npm-debug.log
8
 package-lock.json
8
 package-lock.json
9
+color.json
9
 
10
 
10
 #ignore file or folder about cypress tests
11
 #ignore file or folder about cypress tests
11
 functionnal_tests/package.json
12
 functionnal_tests/package.json
12
 functionnal_tests/cypress.json
13
 functionnal_tests/cypress.json
13
 functionnal_tests/node_modules/
14
 functionnal_tests/node_modules/
14
 functionnal_tests/cypress/
15
 functionnal_tests/cypress/
16
+

+ 4 - 1
backend/README.md Zobrazit soubor

85
 
85
 
86
     cp wsgidav.conf.sample wsgidav.conf
86
     cp wsgidav.conf.sample wsgidav.conf
87
 
87
 
88
-## Run Tracim_backend With Uwsgi : great for production ##
88
+if not did before, you need to create a color.json file at root of tracim_v2 :
89
+   
90
+    cp ../color.json.sample ../color.json
89
 
91
 
92
+## Run Tracim_backend With Uwsgi : great for production ##
90
 
93
 
91
 #### Install Uwsgi
94
 #### Install Uwsgi
92
 
95
 

+ 6 - 0
backend/color-test.json Zobrazit soubor

1
+{
2
+  "primary": "#7d4e24",
3
+  "contents/html-document": "#3f52e3",
4
+  "contents/thread": "#ad4cf9",
5
+  "contents/file": "#ff9900"
6
+}

+ 9 - 0
backend/development.ini.sample Zobrazit soubor

35
 
35
 
36
 ### Global
36
 ### Global
37
 
37
 
38
+# Enable debug mode
39
+# debug = True
38
 cache_dir = %(here)s/data
40
 cache_dir = %(here)s/data
39
 # preview generator cache directory
41
 # preview generator cache directory
40
 preview_cache_dir = /tmp/tracim/preview/
42
 preview_cache_dir = /tmp/tracim/preview/
193
 # organisation.
195
 # organisation.
194
 # frontend.dist_folder_path = /home/user/tracim_v2/frontend/dist
196
 # frontend.dist_folder_path = /home/user/tracim_v2/frontend/dist
195
 
197
 
198
+### Color
199
+# check for color.json file in tracim_v2, check by default in tracim_v2 parent
200
+# dir of backend.
201
+# you can set a specific file path here
202
+# color.config_file_path = /home/user/tracim_v2/color.json
203
+
204
+
196
 ###
205
 ###
197
 # wsgi server configuration
206
 # wsgi server configuration
198
 ###
207
 ###

+ 0 - 1
backend/setup.py Zobrazit soubor

43
     'rq',
43
     'rq',
44
     # frontend file serve
44
     # frontend file serve
45
     'pyramid_mako',
45
     'pyramid_mako',
46
-    'spectra',
47
 ]
46
 ]
48
 
47
 
49
 tests_require = [
48
 tests_require = [

+ 19 - 0
backend/tests_configs.ini Zobrazit soubor

5
 user.auth_token.validity = 604800
5
 user.auth_token.validity = 604800
6
 preview_cache_dir = /tmp/test/preview_cache
6
 preview_cache_dir = /tmp/test/preview_cache
7
 website.base_url = http://localhost:6543
7
 website.base_url = http://localhost:6543
8
+color.config_file_path = %(here)s/color-test.json
9
+
8
 [app:command_test]
10
 [app:command_test]
9
 use = egg:tracim_backend
11
 use = egg:tracim_backend
10
 sqlalchemy.url = sqlite:///tracim_test.sqlite
12
 sqlalchemy.url = sqlite:///tracim_test.sqlite
13
 user.auth_token.validity = 604800
15
 user.auth_token.validity = 604800
14
 preview_cache_dir = /tmp/test/preview_cache
16
 preview_cache_dir = /tmp/test/preview_cache
15
 website.base_url = http://localhost:6543
17
 website.base_url = http://localhost:6543
18
+color.config_file_path = %(here)s/color-test.json
16
 
19
 
17
 [mail_test]
20
 [mail_test]
18
 sqlalchemy.url = sqlite:///:memory:
21
 sqlalchemy.url = sqlite:///:memory:
39
 email.notification.smtp.user = test_user
42
 email.notification.smtp.user = test_user
40
 email.notification.smtp.password = just_a_password
43
 email.notification.smtp.password = just_a_password
41
 website.base_url = http://localhost:6543
44
 website.base_url = http://localhost:6543
45
+color.config_file_path = %(here)s/color-test.json
42
 
46
 
43
 [mail_test_async]
47
 [mail_test_async]
44
 sqlalchemy.url = sqlite:///:memory:
48
 sqlalchemy.url = sqlite:///:memory:
66
 email.notification.smtp.user = test_user
70
 email.notification.smtp.user = test_user
67
 email.notification.smtp.password = just_a_password
71
 email.notification.smtp.password = just_a_password
68
 website.base_url = http://localhost:6543
72
 website.base_url = http://localhost:6543
73
+color.config_file_path = %(here)s/color-test.json
69
 
74
 
70
 [functional_test]
75
 [functional_test]
71
 sqlalchemy.url = sqlite:///tracim_test.sqlite
76
 sqlalchemy.url = sqlite:///tracim_test.sqlite
76
 preview.jpg.restricted_dims = True
81
 preview.jpg.restricted_dims = True
77
 email.notification.activated = false
82
 email.notification.activated = false
78
 website.base_url = http://localhost:6543
83
 website.base_url = http://localhost:6543
84
+color.config_file_path = %(here)s/color-test.json
79
 
85
 
80
 [functional_test_no_db]
86
 [functional_test_no_db]
81
 sqlalchemy.url = sqlite://
87
 sqlalchemy.url = sqlite://
86
 preview.jpg.restricted_dims = True
92
 preview.jpg.restricted_dims = True
87
 email.notification.activated = false
93
 email.notification.activated = false
88
 website.base_url = http://localhost:6543
94
 website.base_url = http://localhost:6543
95
+color.config_file_path = %(here)s/color-test.json
89
 
96
 
90
 [functional_test_with_mail_test_sync]
97
 [functional_test_with_mail_test_sync]
91
 sqlalchemy.url = sqlite:///tracim_test.sqlite
98
 sqlalchemy.url = sqlite:///tracim_test.sqlite
111
 email.notification.smtp.user = test_user
118
 email.notification.smtp.user = test_user
112
 email.notification.smtp.password = just_a_password
119
 email.notification.smtp.password = just_a_password
113
 website.base_url = http://localhost:6543
120
 website.base_url = http://localhost:6543
121
+color.config_file_path = %(here)s/color-test.json
114
 
122
 
115
 [functional_test_with_mail_test_async]
123
 [functional_test_with_mail_test_async]
116
 sqlalchemy.url = sqlite:///tracim_test.sqlite
124
 sqlalchemy.url = sqlite:///tracim_test.sqlite
136
 email.notification.smtp.user = test_user
144
 email.notification.smtp.user = test_user
137
 email.notification.smtp.password = just_a_password
145
 email.notification.smtp.password = just_a_password
138
 website.base_url = http://localhost:6543
146
 website.base_url = http://localhost:6543
147
+color.config_file_path = %(here)s/color-test.json
148
+
149
+[webdav_test]
150
+website.base_url = http://localhost:6543
151
+sqlalchemy.url = sqlite:///:memory:
152
+user.auth_token.validity = 604800
153
+depot_storage_dir = /tmp/test/depot
154
+depot_storage_name = test
155
+preview_cache_dir = /tmp/test/preview_cache
156
+color.config_file_path = %(here)s/color-test.json
157
+wsgidav.config_path = %(here)s/wsgidav-test.conf

+ 76 - 0
backend/tracim_backend/app_models/applications.py Zobrazit soubor

1
+# coding=utf-8
2
+import typing
3
+
4
+from tracim_backend.app_models.contents import ContentType
5
+if typing.TYPE_CHECKING:
6
+    from tracim_backend.config import CFG
7
+    from tracim_backend.app_models.contents import ContentStatus
8
+
9
+
10
+class Application(object):
11
+    """
12
+    Application class with data needed for frontend
13
+    """
14
+    def __init__(
15
+            self,
16
+            label: str,
17
+            slug: str,
18
+            fa_icon: str,
19
+            is_active: bool,
20
+            config: typing.Dict[str, str],
21
+            main_route: str,
22
+            app_config: 'CFG',
23
+    ) -> None:
24
+        """
25
+        @param label: public label of application
26
+        @param slug: identifier of application
27
+        @param fa_icon: font awesome icon class
28
+        @param is_active: True if application enable, False if inactive
29
+        @param config: a dict with eventual application config
30
+        @param main_route: the route of the frontend "home" screen of
31
+        the application. For exemple, if you have an application
32
+        called "calendar", the main route will be something
33
+        like /#/workspace/{wid}/calendar.
34
+        """
35
+        self.label = label
36
+        self.slug = slug
37
+        self.fa_icon = fa_icon
38
+        self.hexcolor = self._get_hexcolor_or_default(slug, app_config)
39
+        self.is_active = is_active
40
+        self.config = config
41
+        self.main_route = main_route
42
+        self.content_types = []
43
+
44
+    # TODO - G.M - 2018-08-07 - Refactor slug coherence issue like this one.
45
+    # we probably should not have 2 kind of slug
46
+    @property
47
+    def minislug(self):
48
+        return self.slug.replace('contents/', '')
49
+
50
+    def add_content_type(
51
+            self,
52
+            label: str,
53
+            slug: str,
54
+            creation_label: str,
55
+            available_statuses: typing.List['ContentStatus'],
56
+            slug_alias: typing.List[str] = None,
57
+            allow_sub_content: bool = False,
58
+    ):
59
+        content_type = ContentType(
60
+            slug=slug,
61
+            fa_icon=self.fa_icon,
62
+            label=label,
63
+            hexcolor=self.hexcolor,
64
+            creation_label=creation_label,
65
+            available_statuses=available_statuses,
66
+            slug_alias=slug_alias,
67
+            allow_sub_content=allow_sub_content,
68
+        )
69
+        self.content_types.append(content_type)
70
+
71
+    def _get_hexcolor_or_default(self, slug: str, app_config: 'CFG') -> str:
72
+        assert app_config.APPS_COLORS
73
+        assert 'primary' in app_config.APPS_COLORS
74
+        if slug in app_config.APPS_COLORS:
75
+            return app_config.APPS_COLORS[slug]
76
+        return app_config.APPS_COLORS['primary']

backend/tracim_backend/models/contents.py → backend/tracim_backend/app_models/contents.py Zobrazit soubor

2
 import typing
2
 import typing
3
 from enum import Enum
3
 from enum import Enum
4
 
4
 
5
+from tracim_backend.extensions import app_list
5
 from tracim_backend.exceptions import ContentTypeNotExist
6
 from tracim_backend.exceptions import ContentTypeNotExist
6
 from tracim_backend.exceptions import ContentStatusNotExist
7
 from tracim_backend.exceptions import ContentStatusNotExist
7
-from tracim_backend.models.applications import html_documents
8
-from tracim_backend.models.applications import _file
9
-from tracim_backend.models.applications import folder
10
-from tracim_backend.models.applications import thread
11
-from tracim_backend.models.applications import markdownpluspage
12
-
13
 
8
 
14
 ####
9
 ####
15
 # Content Status
10
 # Content Status
11
+from tracim_backend.lib.core.application import ApplicationApi
12
+if typing.TYPE_CHECKING:
13
+    from tracim_backend.app_models.applications import Application
16
 
14
 
17
 
15
 
18
 class GlobalStatus(Enum):
16
 class GlobalStatus(Enum):
134
         self.allow_sub_content = allow_sub_content
132
         self.allow_sub_content = allow_sub_content
135
 
133
 
136
 
134
 
137
-thread_type = ContentType(
138
-    slug='thread',
139
-    fa_icon=thread.fa_icon,
140
-    hexcolor=thread.hexcolor,
141
-    label='Thread',
142
-    creation_label='Discuss about a topic',
143
-    available_statuses=CONTENT_STATUS.get_all(),
144
-)
145
-
146
-file_type = ContentType(
147
-    slug='file',
148
-    fa_icon=_file.fa_icon,
149
-    hexcolor=_file.hexcolor,
150
-    label='File',
151
-    creation_label='Upload a file',
152
-    available_statuses=CONTENT_STATUS.get_all(),
153
-)
154
-
155
-markdownpluspage_type = ContentType(
156
-    slug='markdownpage',
157
-    fa_icon=markdownpluspage.fa_icon,
158
-    hexcolor=markdownpluspage.hexcolor,
159
-    label='Rich Markdown File',
160
-    creation_label='Create a Markdown document',
161
-    available_statuses=CONTENT_STATUS.get_all(),
162
-)
163
-
164
-html_documents_type = ContentType(
165
-    slug='html-document',
166
-    fa_icon=html_documents.fa_icon,
167
-    hexcolor=html_documents.hexcolor,
168
-    label='Text Document',
169
-    creation_label='Write a document',
170
-    available_statuses=CONTENT_STATUS.get_all(),
171
-    slug_alias=['page']
172
-)
173
-
174
-# TODO - G.M - 31-05-2018 - Set Better folder params
175
-folder_type = ContentType(
176
-    slug='folder',
177
-    fa_icon=folder.fa_icon,
178
-    hexcolor=folder.hexcolor,
179
-    label='Folder',
180
-    creation_label='Create a folder',
181
-    available_statuses=CONTENT_STATUS.get_all(),
182
-    allow_sub_content=True,
183
-)
184
-
135
+THREAD_TYPE = 'thread'
136
+FILE_TYPE = 'file'
137
+MARKDOWNPLUSPAGE_TYPE = 'markdownpage'
138
+HTML_DOCUMENTS_TYPE = 'html-document'
139
+FOLDER_TYPE = 'folder'
185
 
140
 
186
 # TODO - G.M - 31-05-2018 - Set Better Event params
141
 # TODO - G.M - 31-05-2018 - Set Better Event params
187
 event_type = ContentType(
142
 event_type = ContentType(
188
     slug='event',
143
     slug='event',
189
-    fa_icon=thread.fa_icon,
190
-    hexcolor=thread.hexcolor,
144
+    fa_icon='',
145
+    hexcolor='',
191
     label='Event',
146
     label='Event',
192
     creation_label='Event',
147
     creation_label='Event',
193
     available_statuses=CONTENT_STATUS.get_all(),
148
     available_statuses=CONTENT_STATUS.get_all(),
196
 # TODO - G.M - 31-05-2018 - Set Better Event params
151
 # TODO - G.M - 31-05-2018 - Set Better Event params
197
 comment_type = ContentType(
152
 comment_type = ContentType(
198
     slug='comment',
153
     slug='comment',
199
-    fa_icon=thread.fa_icon,
200
-    hexcolor=thread.hexcolor,
154
+    fa_icon='',
155
+    hexcolor='',
201
     label='Comment',
156
     label='Comment',
202
     creation_label='Comment',
157
     creation_label='Comment',
203
     available_statuses=CONTENT_STATUS.get_all(),
158
     available_statuses=CONTENT_STATUS.get_all(),
209
     ContentType List
164
     ContentType List
210
     """
165
     """
211
     Any_SLUG = 'any'
166
     Any_SLUG = 'any'
212
-    Folder = folder_type
213
     Comment = comment_type
167
     Comment = comment_type
214
     Event = event_type
168
     Event = event_type
215
-    File = file_type
216
-    Page = html_documents_type
217
-    Thread = thread_type
218
 
169
 
219
-    def __init__(self, extend_content_status: typing.List[ContentType]):
220
-        self._content_types = [self.Folder]
221
-        self._content_types.extend(extend_content_status)
170
+    @property
171
+    def Folder(self):
172
+        return self.get_one_by_slug(FOLDER_TYPE)
173
+
174
+    @property
175
+    def File(self):
176
+        return self.get_one_by_slug(FILE_TYPE)
177
+
178
+    @property
179
+    def Page(self):
180
+        return self.get_one_by_slug(HTML_DOCUMENTS_TYPE)
181
+
182
+    @property
183
+    def Thread(self):
184
+        return self.get_one_by_slug(THREAD_TYPE)
185
+
186
+    def __init__(self, app_list: typing.List['Application']):
187
+        self.app_list = app_list
222
         self._special_contents_types = [self.Comment]
188
         self._special_contents_types = [self.Comment]
223
         self._extra_slugs = [self.Any_SLUG]
189
         self._extra_slugs = [self.Any_SLUG]
224
 
190
 
191
+    @property
192
+    def _content_types(self):
193
+        app_api = ApplicationApi(self.app_list)
194
+        content_types = app_api.get_content_types()
195
+        return content_types
196
+
225
     def get_one_by_slug(self, slug: str) -> ContentType:
197
     def get_one_by_slug(self, slug: str) -> ContentType:
226
         """
198
         """
227
         Get ContentType object according to slug
199
         Get ContentType object according to slug
235
                 return item
207
                 return item
236
         raise ContentTypeNotExist()
208
         raise ContentTypeNotExist()
237
 
209
 
238
-    def endpoint_allowed_types_slug(self) -> typing.List[str]:
210
+    def restricted_allowed_types_slug(self) -> typing.List[str]:
239
         """
211
         """
240
-        Return restricted list of content_type:
241
-        dont return special content_type like  comment, don't return
212
+        Return restricted list of content_type: don't return
242
         "any" slug, dont return content type slug alias , don't return event.
213
         "any" slug, dont return content type slug alias , don't return event.
243
         Useful to restrict slug param in schema.
214
         Useful to restrict slug param in schema.
244
         """
215
         """
245
         allowed_type_slug = [contents_type.slug for contents_type in self._content_types]  # nopep8
216
         allowed_type_slug = [contents_type.slug for contents_type in self._content_types]  # nopep8
246
         return allowed_type_slug
217
         return allowed_type_slug
247
 
218
 
248
-    def extended_endpoint_allowed_types_slug(self) -> typing.List[str]:
249
-        allowed_types_slug = self.endpoint_allowed_types_slug().copy()
250
-        for content_type in self._special_contents_types:
251
-            allowed_types_slug.append(content_type.slug)
252
-        return allowed_types_slug
219
+    def endpoint_allowed_types_slug(self) -> typing.List[str]:
220
+        """
221
+        Same as restricted_allowed_types_slug but with special content_type
222
+        included like comments.
223
+        """
224
+        content_types = self._content_types
225
+        content_types.extend(self._special_contents_types)
226
+        allowed_type_slug = [contents_type.slug for contents_type in content_types]  # nopep8
227
+        return allowed_type_slug
253
 
228
 
254
     def query_allowed_types_slugs(self) -> typing.List[str]:
229
     def query_allowed_types_slugs(self) -> typing.List[str]:
255
         """
230
         """
258
         Usefull allowed value to perform query to database.
233
         Usefull allowed value to perform query to database.
259
         """
234
         """
260
         allowed_types_slug = []
235
         allowed_types_slug = []
261
-        for content_type in self._content_types:
236
+        content_types = self._content_types
237
+        content_types.extend(self._special_contents_types)
238
+        for content_type in content_types:
262
             allowed_types_slug.append(content_type.slug)
239
             allowed_types_slug.append(content_type.slug)
263
             if content_type.slug_alias:
240
             if content_type.slug_alias:
264
                 allowed_types_slug.extend(content_type.slug_alias)
241
                 allowed_types_slug.extend(content_type.slug_alias)
265
-        for content_type in self._special_contents_types:
266
-            allowed_types_slug.append(content_type.slug)
267
         allowed_types_slug.extend(self._extra_slugs)
242
         allowed_types_slug.extend(self._extra_slugs)
268
         return allowed_types_slug
243
         return allowed_types_slug
269
 
244
 
270
     def default_allowed_content_properties(self, slug) -> dict:
245
     def default_allowed_content_properties(self, slug) -> dict:
271
         content_type = self.get_one_by_slug(slug)
246
         content_type = self.get_one_by_slug(slug)
272
         if content_type.allow_sub_content:
247
         if content_type.allow_sub_content:
273
-            sub_content_allowed = self.extended_endpoint_allowed_types_slug()
248
+            sub_content_allowed = self.endpoint_allowed_types_slug()
274
         else:
249
         else:
275
             sub_content_allowed = [self.Comment.slug]
250
             sub_content_allowed = [self.Comment.slug]
276
 
251
 
280
         return properties_dict
255
         return properties_dict
281
 
256
 
282
 
257
 
283
-CONTENT_TYPES = ContentTypeList(
284
-    [
285
-        thread_type,
286
-        file_type,
287
-        # TODO - G.M - 2018-08-02 - Restore markdown page content
288
-        #    markdownpluspage_type,
289
-        html_documents_type,
290
-    ]
291
-)
258
+CONTENT_TYPES = ContentTypeList(app_list)

+ 11 - 0
backend/tracim_backend/app_models/validator.py Zobrazit soubor

1
+from marshmallow.validate import OneOf
2
+from tracim_backend.app_models.contents import CONTENT_TYPES
3
+
4
+# TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
5
+# of tracim_backend, Be careful all_content_types_validator is a global_var !
6
+
7
+all_content_types_validator = OneOf(choices=[])
8
+
9
+
10
+def update_validators():
11
+    all_content_types_validator.choices = CONTENT_TYPES.endpoint_allowed_types_slug()  # nopep8

+ 33 - 0
backend/tracim_backend/app_models/workspace_menu_entries.py Zobrazit soubor

1
+class WorkspaceMenuEntry(object):
2
+    """
3
+    Application class with data needed for frontend
4
+    """
5
+    def __init__(
6
+            self,
7
+            label: str,
8
+            slug: str,
9
+            fa_icon: str,
10
+            hexcolor: str,
11
+            route: str,
12
+    ) -> None:
13
+        self.slug = slug
14
+        self.label = label
15
+        self.route = route
16
+        self.hexcolor = hexcolor
17
+        self.fa_icon = fa_icon
18
+
19
+
20
+dashboard_menu_entry = WorkspaceMenuEntry(
21
+  slug='dashboard',
22
+  label='Dashboard',
23
+  route='/#/workspaces/{workspace_id}/dashboard',
24
+  hexcolor='#252525',
25
+  fa_icon="signal",
26
+)
27
+all_content_menu_entry = WorkspaceMenuEntry(
28
+  slug="contents/all",
29
+  label="All Contents",
30
+  route="/#/workspaces/{workspace_id}/contents",
31
+  hexcolor="#fdfdfd",
32
+  fa_icon="th",
33
+)

+ 149 - 4
backend/tracim_backend/config.py Zobrazit soubor

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
+import json
2
 from urllib.parse import urlparse
3
 from urllib.parse import urlparse
3
 
4
 
4
 import os
5
 import os
5
 from paste.deploy.converters import asbool
6
 from paste.deploy.converters import asbool
7
+from tracim_backend.app_models.validator import update_validators
8
+from tracim_backend.extensions import app_list
6
 from tracim_backend.lib.utils.logger import logger
9
 from tracim_backend.lib.utils.logger import logger
7
 from depot.manager import DepotManager
10
 from depot.manager import DepotManager
8
-from tracim_backend.models.contents import CONTENT_TYPES
11
+from tracim_backend.app_models.applications import Application
12
+from tracim_backend.app_models.contents import CONTENT_TYPES
13
+from tracim_backend.app_models.contents import CONTENT_STATUS
9
 from tracim_backend.models.data import ActionDescription
14
 from tracim_backend.models.data import ActionDescription
10
 
15
 
11
 
16
 
12
-
13
 class CFG(object):
17
 class CFG(object):
14
     """Object used for easy access to config file parameters."""
18
     """Object used for easy access to config file parameters."""
15
 
19
 
41
         ###
45
         ###
42
         # General
46
         # General
43
         ###
47
         ###
48
+        backend_folder = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # nopep8
49
+        tracim_v2_folder = os.path.dirname(backend_folder)
50
+        default_color_config_file_path = os.path.join(tracim_v2_folder, 'color.json')  # nopep8
51
+        self.COLOR_CONFIG_FILE_PATH = settings.get(
52
+            'color.config_file_path', default_color_config_file_path
53
+        )
54
+        if not os.path.exists(self.COLOR_CONFIG_FILE_PATH):
55
+            raise Exception(
56
+                'ERROR: {} file does not exist. '
57
+                'please create it or set color.config_file_path'
58
+                'with a correct value'.format(self.COLOR_CONFIG_FILE_PATH)
59
+            )
60
+
61
+        try:
62
+            with open(self.COLOR_CONFIG_FILE_PATH) as json_file:
63
+                self.APPS_COLORS = json.load(json_file)
64
+        except Exception as e:
65
+            raise Exception(
66
+                'Error: {} file could not be load as json'.format(self.COLOR_CONFIG_FILE_PATH) # nopep8
67
+            ) from e
44
 
68
 
69
+        try:
70
+            self.APPS_COLORS['primary']
71
+        except KeyError as e:
72
+            raise Exception(
73
+                'Error: primary color is required in {} file'.format(
74
+                    self.COLOR_CONFIG_FILE_PATH)  # nopep8
75
+            ) from e
76
+
77
+        self._set_default_app()
45
         mandatory_msg = \
78
         mandatory_msg = \
46
             'ERROR: {} configuration is mandatory. Set it before continuing.'
79
             'ERROR: {} configuration is mandatory. Set it before continuing.'
47
         self.DEPOT_STORAGE_DIR = settings.get(
80
         self.DEPOT_STORAGE_DIR = settings.get(
450
         # INFO - G.M - 2018-08-06 - we pretend that frontend_dist_folder
483
         # INFO - G.M - 2018-08-06 - we pretend that frontend_dist_folder
451
         # is probably in frontend subfolder
484
         # is probably in frontend subfolder
452
         # of tracim_v2 parent of both backend and frontend
485
         # of tracim_v2 parent of both backend and frontend
453
-        backend_folder = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # nopep8
454
-        tracim_v2_folder = os.path.dirname(backend_folder)
455
         frontend_dist_folder = os.path.join(tracim_v2_folder, 'frontend', 'dist')  # nopep8
486
         frontend_dist_folder = os.path.join(tracim_v2_folder, 'frontend', 'dist')  # nopep8
456
 
487
 
457
         self.FRONTEND_DIST_FOLDER_PATH = settings.get(
488
         self.FRONTEND_DIST_FOLDER_PATH = settings.get(
467
             )
498
             )
468
 
499
 
469
     def configure_filedepot(self):
500
     def configure_filedepot(self):
501
+
502
+        # TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
503
+        # of tracim_backend, Be careful DepotManager is a Singleton !
504
+
470
         depot_storage_name = self.DEPOT_STORAGE_NAME
505
         depot_storage_name = self.DEPOT_STORAGE_NAME
471
         depot_storage_path = self.DEPOT_STORAGE_DIR
506
         depot_storage_path = self.DEPOT_STORAGE_DIR
472
         depot_storage_settings = {'depot.storage_path': depot_storage_path}
507
         depot_storage_settings = {'depot.storage_path': depot_storage_path}
475
             depot_storage_settings,
510
             depot_storage_settings,
476
         )
511
         )
477
 
512
 
513
+    def _set_default_app(self):
514
+        calendar = Application(
515
+            label='Calendar',
516
+            slug='calendar',
517
+            fa_icon='calendar',
518
+            is_active=False,
519
+            config={},
520
+            main_route='/#/workspaces/{workspace_id}/calendar',
521
+            app_config=self
522
+        )
523
+
524
+        thread = Application(
525
+            label='Threads',
526
+            slug='contents/thread',
527
+            fa_icon='comments-o',
528
+            is_active=True,
529
+            config={},
530
+            main_route='/#/workspaces/{workspace_id}/contents?type=thread',
531
+            app_config=self
532
+        )
533
+        thread.add_content_type(
534
+            slug='thread',
535
+            label='Thread',
536
+            creation_label='Discuss about a topic',
537
+            available_statuses=CONTENT_STATUS.get_all(),
538
+        )
539
+
540
+        folder = Application(
541
+            label='Folder',
542
+            slug='contents/folder',
543
+            fa_icon='folder-open-o',
544
+            is_active=True,
545
+            config={},
546
+            main_route='',
547
+            app_config=self
548
+        )
549
+        folder.add_content_type(
550
+            slug='folder',
551
+            label='Folder',
552
+            creation_label='Create a folder',
553
+            available_statuses=CONTENT_STATUS.get_all(),
554
+            allow_sub_content=True,
555
+        )
556
+
557
+        _file = Application(
558
+            label='Files',
559
+            slug='contents/file',
560
+            fa_icon='paperclip',
561
+            is_active=True,
562
+            config={},
563
+            main_route='/#/workspaces/{workspace_id}/contents?type=file',
564
+            app_config=self,
565
+        )
566
+        _file.add_content_type(
567
+            slug='file',
568
+            label='File',
569
+            creation_label='Upload a file',
570
+            available_statuses=CONTENT_STATUS.get_all(),
571
+        )
572
+
573
+        markdownpluspage = Application(
574
+            label='Markdown Plus Documents',
575
+            # TODO - G.M - 24-05-2018 - Check label
576
+            slug='content/markdownpluspage',
577
+            fa_icon='file-code-o',
578
+            is_active=False,
579
+            config={},
580
+            main_route='/#/workspaces/{workspace_id}/contents?type=markdownpluspage',
581
+            # nopep8
582
+            app_config=self,
583
+        )
584
+        markdownpluspage.add_content_type(
585
+            slug='markdownpage',
586
+            label='Rich Markdown File',
587
+            creation_label='Create a Markdown document',
588
+            available_statuses=CONTENT_STATUS.get_all(),
589
+        )
590
+
591
+        html_documents = Application(
592
+            label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
593
+            slug='contents/html-document',
594
+            fa_icon='file-text-o',
595
+            is_active=True,
596
+            config={},
597
+            main_route='/#/workspaces/{workspace_id}/contents?type=html-document',
598
+            app_config=self
599
+        )
600
+        html_documents.add_content_type(
601
+            slug='html-document',
602
+            label='Text Document',
603
+            creation_label='Write a document',
604
+            available_statuses=CONTENT_STATUS.get_all(),
605
+            slug_alias=['page']
606
+        )
607
+
608
+        # TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
609
+        # of tracim_backend, Be careful app_list is a global_var
610
+        app_list.clear()
611
+        app_list.extend([
612
+            html_documents,
613
+            markdownpluspage,
614
+            _file,
615
+            thread,
616
+            folder,
617
+            calendar,
618
+        ])
619
+        # TODO - G.M - 2018-08-08 - We need to update validators each time
620
+        # app_list is updated.
621
+        update_validators()
622
+
478
     class CST(object):
623
     class CST(object):
479
         ASYNC = 'ASYNC'
624
         ASYNC = 'ASYNC'
480
         SYNC = 'SYNC'
625
         SYNC = 'SYNC'

+ 6 - 0
backend/tracim_backend/exceptions.py Zobrazit soubor

204
 class PreviewDimNotAllowed(TracimException):
204
 class PreviewDimNotAllowed(TracimException):
205
     pass
205
     pass
206
 
206
 
207
+
207
 class UnallowedSubContent(TracimException):
208
 class UnallowedSubContent(TracimException):
208
     pass
209
     pass
209
 
210
 
211
+
210
 class TooShortAutocompleteString(TracimException):
212
 class TooShortAutocompleteString(TracimException):
211
     pass
213
     pass
212
 
214
 
215
     pass
217
     pass
216
 
218
 
217
 
219
 
220
+class AppDoesNotExist(TracimException):
221
+    pass
222
+
223
+
218
 class EmailAlreadyExistInDb(TracimException):
224
 class EmailAlreadyExistInDb(TracimException):
219
     pass
225
     pass

+ 11 - 0
backend/tracim_backend/extensions.py Zobrazit soubor

1
 from hapic import Hapic
1
 from hapic import Hapic
2
 
2
 
3
 hapic = Hapic()
3
 hapic = Hapic()
4
+
5
+# TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var of tracim_backend
6
+
7
+# INFO - G.M - 2018-08-08 - app_list
8
+# app_list is one of the few "global_val" in tracim_backend, with hapic
9
+# and all_content_types_validator.
10
+# The goal of this is to be able to get current list of loaded app.
11
+# List is empty until config load apps.
12
+# If you need to update app_list, think about updating Content validator like
13
+# all_content_types_validator , see  update_validators() method.
14
+app_list = []

+ 1 - 1
backend/tracim_backend/fixtures/content.py Zobrazit soubor

8
 from tracim_backend.lib.core.content import ContentApi
8
 from tracim_backend.lib.core.content import ContentApi
9
 from tracim_backend.lib.core.userworkspace import RoleApi
9
 from tracim_backend.lib.core.userworkspace import RoleApi
10
 from tracim_backend.lib.core.workspace import WorkspaceApi
10
 from tracim_backend.lib.core.workspace import WorkspaceApi
11
-from tracim_backend.models.contents import CONTENT_TYPES
11
+from tracim_backend.app_models.contents import CONTENT_TYPES
12
 from tracim_backend.models.data import UserRoleInWorkspace
12
 from tracim_backend.models.data import UserRoleInWorkspace
13
 from tracim_backend.models.revision_protection import new_revision
13
 from tracim_backend.models.revision_protection import new_revision
14
 
14
 

+ 70 - 0
backend/tracim_backend/lib/core/application.py Zobrazit soubor

1
+import typing
2
+from copy import copy
3
+
4
+from tracim_backend.exceptions import AppDoesNotExist
5
+from tracim_backend.app_models.workspace_menu_entries import WorkspaceMenuEntry
6
+from tracim_backend.app_models.workspace_menu_entries import dashboard_menu_entry
7
+from tracim_backend.app_models.workspace_menu_entries import all_content_menu_entry
8
+
9
+
10
+class ApplicationApi(object):
11
+
12
+    def __init__(
13
+        self,
14
+        app_list,
15
+        show_all: bool = False,
16
+    ) ->  None:
17
+        self.apps = app_list
18
+        self.show_all = show_all
19
+
20
+    def get_one(self, slug):
21
+        for app in self.apps:
22
+            if app.slug == slug:
23
+                return app
24
+        raise AppDoesNotExist('Application {app} does not exist'.format(app=slug))  # nopep8
25
+
26
+    def get_all(self):
27
+        active_apps = []
28
+        for app in self.apps:
29
+            if self.show_all or app.is_active:
30
+                active_apps.append(app)
31
+
32
+        return active_apps
33
+
34
+    def get_content_types(self):
35
+        active_content_types = []
36
+        for app in self.get_all():
37
+            if app.content_types:
38
+                for content_type in app.content_types:
39
+                    active_content_types.append(content_type)
40
+        return active_content_types
41
+
42
+    def get_default_workspace_menu_entry(
43
+            self,
44
+            workspace: 'Workspace',
45
+    ) -> typing.List[WorkspaceMenuEntry]:
46
+        """
47
+        Get default menu entry for a workspace
48
+        """
49
+        menu_entries = [
50
+            copy(dashboard_menu_entry),
51
+            copy(all_content_menu_entry),
52
+        ]
53
+        for app in self.get_all():
54
+            if app.main_route:
55
+                new_entry = WorkspaceMenuEntry(
56
+                    slug=app.slug,
57
+                    label=app.label,
58
+                    hexcolor=app.hexcolor,
59
+                    fa_icon=app.fa_icon,
60
+                    route=app.main_route
61
+                )
62
+                menu_entries.append(new_entry)
63
+
64
+        for entry in menu_entries:
65
+            entry.route = entry.route.replace(
66
+                '{workspace_id}',
67
+                str(workspace.workspace_id)
68
+            )
69
+
70
+        return menu_entries

+ 4 - 4
backend/tracim_backend/lib/core/content.py Zobrazit soubor

36
 from tracim_backend.exceptions import ContentNotFound
36
 from tracim_backend.exceptions import ContentNotFound
37
 from tracim_backend.exceptions import WorkspacesDoNotMatch
37
 from tracim_backend.exceptions import WorkspacesDoNotMatch
38
 from tracim_backend.lib.utils.utils import current_date_for_filename
38
 from tracim_backend.lib.utils.utils import current_date_for_filename
39
-from tracim_backend.models.contents import CONTENT_STATUS
40
-from tracim_backend.models.contents import ContentType
41
-from tracim_backend.models.contents import CONTENT_TYPES
39
+from tracim_backend.app_models.contents import CONTENT_STATUS
40
+from tracim_backend.app_models.contents import ContentType
41
+from tracim_backend.app_models.contents import CONTENT_TYPES
42
 from tracim_backend.models.revision_protection import new_revision
42
 from tracim_backend.models.revision_protection import new_revision
43
 from tracim_backend.models.auth import User
43
 from tracim_backend.models.auth import User
44
 from tracim_backend.models.data import ActionDescription
44
 from tracim_backend.models.data import ActionDescription
1137
         """
1137
         """
1138
         allowed_content_dict = {}
1138
         allowed_content_dict = {}
1139
         for allowed_content_type_slug in allowed_content_type_slug_list:
1139
         for allowed_content_type_slug in allowed_content_type_slug_list:
1140
-            if allowed_content_type_slug not in CONTENT_TYPES.extended_endpoint_allowed_types_slug():
1140
+            if allowed_content_type_slug not in CONTENT_TYPES.endpoint_allowed_types_slug():
1141
                 raise ContentTypeNotExist('Content_type {} does not exist'.format(allowed_content_type_slug))  # nopep8
1141
                 raise ContentTypeNotExist('Content_type {} does not exist'.format(allowed_content_type_slug))  # nopep8
1142
             allowed_content_dict[allowed_content_type_slug] = True
1142
             allowed_content_dict[allowed_content_type_slug] = True
1143
 
1143
 

+ 1 - 1
backend/tracim_backend/lib/mail_notifier/notifier.py Zobrazit soubor

20
 from tracim_backend.lib.utils.utils import get_login_frontend_url
20
 from tracim_backend.lib.utils.utils import get_login_frontend_url
21
 from tracim_backend.lib.utils.utils import get_email_logo_frontend_url
21
 from tracim_backend.lib.utils.utils import get_email_logo_frontend_url
22
 from tracim_backend.models.auth import User
22
 from tracim_backend.models.auth import User
23
-from tracim_backend.models.contents import CONTENT_TYPES
23
+from tracim_backend.app_models.contents import CONTENT_TYPES
24
 from tracim_backend.models.context_models import ContentInContext
24
 from tracim_backend.models.context_models import ContentInContext
25
 from tracim_backend.models.context_models import WorkspaceInContext
25
 from tracim_backend.models.context_models import WorkspaceInContext
26
 from tracim_backend.models.data import ActionDescription
26
 from tracim_backend.models.data import ActionDescription

+ 1 - 1
backend/tracim_backend/lib/utils/authentification.py Zobrazit soubor

3
 from pyramid.request import Request
3
 from pyramid.request import Request
4
 from sqlalchemy.orm.exc import NoResultFound
4
 from sqlalchemy.orm.exc import NoResultFound
5
 
5
 
6
-from tracim_backend import TracimRequest
6
+from tracim_backend.lib.utils.request import TracimRequest
7
 from tracim_backend.exceptions import UserDoesNotExist
7
 from tracim_backend.exceptions import UserDoesNotExist
8
 from tracim_backend.lib.core.user import UserApi
8
 from tracim_backend.lib.core.user import UserApi
9
 from tracim_backend.models import User
9
 from tracim_backend.models import User

+ 5 - 7
backend/tracim_backend/lib/utils/authorization.py Zobrazit soubor

5
 from pyramid.interfaces import IAuthorizationPolicy
5
 from pyramid.interfaces import IAuthorizationPolicy
6
 from zope.interface import implementer
6
 from zope.interface import implementer
7
 
7
 
8
-from tracim_backend.models.contents import ContentType
9
-from tracim_backend.models.contents import CONTENT_TYPES
8
+from tracim_backend.app_models.contents import ContentType
9
+from tracim_backend.app_models.contents import CONTENT_TYPES
10
 
10
 
11
 try:
11
 try:
12
     from json.decoder import JSONDecodeError
12
     from json.decoder import JSONDecodeError
13
 except ImportError:  # python3.4
13
 except ImportError:  # python3.4
14
     JSONDecodeError = ValueError
14
     JSONDecodeError = ValueError
15
 
15
 
16
-from tracim_backend.models.contents import ContentType
17
 from tracim_backend.exceptions import InsufficientUserRoleInWorkspace
16
 from tracim_backend.exceptions import InsufficientUserRoleInWorkspace
18
 from tracim_backend.exceptions import ContentTypeNotAllowed
17
 from tracim_backend.exceptions import ContentTypeNotAllowed
19
 from tracim_backend.exceptions import InsufficientUserProfile
18
 from tracim_backend.exceptions import InsufficientUserProfile
167
     return decorator
166
     return decorator
168
 
167
 
169
 
168
 
170
-def require_content_types(content_types: typing.List['ContentType']) -> typing.Callable:  # nopep8
169
+def require_content_types(content_types_slug: typing.List[str]) -> typing.Callable:  # nopep8
171
     """
170
     """
172
     Restricts access to specific file type or raise an exception.
171
     Restricts access to specific file type or raise an exception.
173
     Check role for candidate_workspace.
172
     Check role for candidate_workspace.
174
-    :param content_types: list of ContentType object
173
+    :param content_types_slug: list of slug of content_types
175
     :return: decorator
174
     :return: decorator
176
     """
175
     """
177
     def decorator(func: typing.Callable) -> typing.Callable:
176
     def decorator(func: typing.Callable) -> typing.Callable:
178
         @functools.wraps(func)
177
         @functools.wraps(func)
179
         def wrapper(self, context, request: 'TracimRequest') -> typing.Callable:
178
         def wrapper(self, context, request: 'TracimRequest') -> typing.Callable:
180
             content = request.current_content
179
             content = request.current_content
181
-            current_content_type_slug = CONTENT_TYPES.get_one_by_slug(content.type).slug
182
-            content_types_slug = [content_type.slug for content_type in content_types]  # nopep8
180
+            current_content_type_slug = CONTENT_TYPES.get_one_by_slug(content.type).slug  # nopep8
183
             if current_content_type_slug in content_types_slug:
181
             if current_content_type_slug in content_types_slug:
184
                 return func(self, context, request)
182
                 return func(self, context, request)
185
             raise ContentTypeNotAllowed()
183
             raise ContentTypeNotAllowed()

+ 1 - 1
backend/tracim_backend/lib/utils/request.py Zobrazit soubor

15
 from tracim_backend.exceptions import UserDoesNotExist
15
 from tracim_backend.exceptions import UserDoesNotExist
16
 from tracim_backend.exceptions import WorkspaceNotFound
16
 from tracim_backend.exceptions import WorkspaceNotFound
17
 from tracim_backend.exceptions import ImmutableAttribute
17
 from tracim_backend.exceptions import ImmutableAttribute
18
-from tracim_backend.models.contents import CONTENT_TYPES
18
+from tracim_backend.app_models.contents import CONTENT_TYPES
19
 from tracim_backend.lib.core.content import ContentApi
19
 from tracim_backend.lib.core.content import ContentApi
20
 from tracim_backend.lib.core.user import UserApi
20
 from tracim_backend.lib.core.user import UserApi
21
 from tracim_backend.lib.core.workspace import WorkspaceApi
21
 from tracim_backend.lib.core.workspace import WorkspaceApi

+ 67 - 6
backend/tracim_backend/lib/utils/utils.py Zobrazit soubor

3
 import random
3
 import random
4
 import string
4
 import string
5
 from enum import Enum
5
 from enum import Enum
6
+import colorsys
6
 
7
 
7
 from redis import Redis
8
 from redis import Redis
8
 from rq import Queue
9
 from rq import Queue
9
-
10
-from tracim_backend.config import CFG
10
+import typing
11
+if typing.TYPE_CHECKING:
12
+    from tracim_backend.config import CFG
11
 
13
 
12
 DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
14
 DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
13
 DEFAULT_WEBDAV_CONFIG_FILE = "wsgidav.conf"
15
 DEFAULT_WEBDAV_CONFIG_FILE = "wsgidav.conf"
16
 WORKSPACE_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}'  # nopep8
18
 WORKSPACE_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}'  # nopep8
17
 
19
 
18
 
20
 
19
-def get_root_frontend_url(config: CFG) -> str:
21
+def get_root_frontend_url(config: 'CFG') -> str:
20
     """
22
     """
21
     Return website base url with always '/' at the end
23
     Return website base url with always '/' at the end
22
     """
24
     """
28
     return base_url
30
     return base_url
29
 
31
 
30
 
32
 
31
-def get_login_frontend_url(config: CFG):
33
+def get_login_frontend_url(config: 'CFG'):
32
     """
34
     """
33
     Return login page url
35
     Return login page url
34
     """
36
     """
35
     return get_root_frontend_url(config) + 'login'
37
     return get_root_frontend_url(config) + 'login'
36
 
38
 
37
 
39
 
38
-def get_email_logo_frontend_url(config: CFG):
40
+def get_email_logo_frontend_url(config: 'CFG'):
39
     # TODO - G.M - 11-06-2018 - [emailTemplateURL] correct value for email_logo_frontend_url  # nopep8
41
     # TODO - G.M - 11-06-2018 - [emailTemplateURL] correct value for email_logo_frontend_url  # nopep8
40
     return 'data:image/png;base64,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'  # nopep8'
42
     return 'data:image/png;base64,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'  # nopep8'
41
 
43
 
42
 
44
 
43
-def get_redis_connection(config: CFG) -> Redis:
45
+def get_redis_connection(config: 'CFG') -> Redis:
44
     """
46
     """
45
     :param config: current app_config
47
     :param config: current app_config
46
     :return: redis connection
48
     :return: redis connection
125
     """
127
     """
126
     return ''.join(random.choice(chars) for char_number in range(length))
128
     return ''.join(random.choice(chars) for char_number in range(length))
127
 
129
 
130
+
131
+def clamp(val: float, minimum: float = 0.0, maximum: float= 255.0) -> int:
132
+    """ Fix value between min an max"""
133
+    if val < minimum:
134
+        return minimum
135
+    if val > maximum:
136
+        return maximum
137
+    return int(val)
138
+
139
+
140
+COLOR_DARKEN_SCALE_FACTOR = 0.85
141
+COLOR_LIGHTEN_SCALE_FACTOR = 1.15
142
+
143
+
144
+class Color(object):
145
+    def __init__(self, base_hex_code: str):
146
+        """
147
+        :param base_hex_code: hex color like '#FFFFFF'
148
+        """
149
+
150
+        assert len(base_hex_code) == 7
151
+        self._base_hex_code = base_hex_code
152
+
153
+    # INFO - G.M - 2018-08-10 - get_hexcolor, inspired by
154
+    # https://thadeusb.com/weblog/2010/10/10/python_scale_hex_color/
155
+
156
+    def get_hexcolor(self, scalefactor: float) -> str:
157
+        """
158
+
159
+        :param scalefactor: factor of scaling,
160
+        value between 0 and 1 darken the color,
161
+        value >1 lighten the color.
162
+        :return: new hex_color
163
+        """
164
+
165
+        hex_color = self._base_hex_code.strip('#')
166
+        assert scalefactor > 0
167
+
168
+        r = int(hex_color[:2], 16)
169
+        g = int(hex_color[2:4], 16)
170
+        b = int(hex_color[4:], 16)
171
+
172
+        h, l, s = colorsys.rgb_to_hls(r, g, b)
173
+        l = scalefactor * l
174
+        r, g, b = colorsys.hls_to_rgb(h, l, s)
175
+
176
+        return "#%02x%02x%02x" % (clamp(r), clamp(g), clamp(b))
177
+
178
+    @property
179
+    def normal(self):
180
+        return self._base_hex_code
181
+
182
+    @property
183
+    def darken(self):
184
+        return self.get_hexcolor(COLOR_DARKEN_SCALE_FACTOR)
185
+
186
+    @property
187
+    def lighten(self):
188
+        return self.get_hexcolor(COLOR_LIGHTEN_SCALE_FACTOR)

+ 1 - 1
backend/tracim_backend/lib/webdav/dav_provider.py Zobrazit soubor

8
 from tracim_backend import CFG
8
 from tracim_backend import CFG
9
 from tracim_backend.lib.webdav.utils import transform_to_bdd, HistoryType, \
9
 from tracim_backend.lib.webdav.utils import transform_to_bdd, HistoryType, \
10
     SpecialFolderExtension
10
     SpecialFolderExtension
11
-from tracim_backend.models.contents import CONTENT_TYPES
11
+from tracim_backend.app_models.contents import CONTENT_TYPES
12
 
12
 
13
 from wsgidav.dav_provider import DAVProvider
13
 from wsgidav.dav_provider import DAVProvider
14
 from wsgidav.lock_manager import LockManager
14
 from wsgidav.lock_manager import LockManager

+ 1 - 1
backend/tracim_backend/lib/webdav/design.py Zobrazit soubor

1
 #coding: utf8
1
 #coding: utf8
2
 from datetime import datetime
2
 from datetime import datetime
3
 
3
 
4
-from tracim_backend.models.contents import CONTENT_TYPES
4
+from tracim_backend.app_models.contents import CONTENT_TYPES
5
 from tracim_backend.models.data import VirtualEvent
5
 from tracim_backend.models.data import VirtualEvent
6
 from tracim_backend.models import data
6
 from tracim_backend.models import data
7
 
7
 

+ 1 - 1
backend/tracim_backend/lib/webdav/resources.py Zobrazit soubor

19
     FakeFileStream
19
     FakeFileStream
20
 from tracim_backend.lib.webdav.utils import transform_to_bdd
20
 from tracim_backend.lib.webdav.utils import transform_to_bdd
21
 from tracim_backend.lib.core.workspace import WorkspaceApi
21
 from tracim_backend.lib.core.workspace import WorkspaceApi
22
-from tracim_backend.models.contents import CONTENT_TYPES
22
+from tracim_backend.app_models.contents import CONTENT_TYPES
23
 from tracim_backend.models.data import User, ContentRevisionRO
23
 from tracim_backend.models.data import User, ContentRevisionRO
24
 from tracim_backend.models.data import Workspace
24
 from tracim_backend.models.data import Workspace
25
 from tracim_backend.models.data import Content
25
 from tracim_backend.models.data import Content

+ 1 - 1
backend/tracim_backend/lib/webdav/utils.py Zobrazit soubor

4
 from os.path import normpath as base_normpath
4
 from os.path import normpath as base_normpath
5
 
5
 
6
 from sqlalchemy.orm import Session
6
 from sqlalchemy.orm import Session
7
-from tracim_backend.models.contents import CONTENT_TYPES
7
+from tracim_backend.app_models.contents import CONTENT_TYPES
8
 from wsgidav import util
8
 from wsgidav import util
9
 from wsgidav import compat
9
 from wsgidav import compat
10
 
10
 

+ 1 - 1
backend/tracim_backend/models/__init__.py Zobrazit soubor

5
 from sqlalchemy.orm import configure_mappers
5
 from sqlalchemy.orm import configure_mappers
6
 import zope.sqlalchemy
6
 import zope.sqlalchemy
7
 from .meta import DeclarativeBase
7
 from .meta import DeclarativeBase
8
-from .revision_protection import prevent_content_revision_delete
8
+from tracim_backend.models.revision_protection import prevent_content_revision_delete
9
 # import or define all models here to ensure they are attached to the
9
 # import or define all models here to ensure they are attached to the
10
 # Base.metadata prior to any initialization routines
10
 # Base.metadata prior to any initialization routines
11
 from tracim_backend.models.auth import User, Group, Permission
11
 from tracim_backend.models.auth import User, Group, Permission

+ 0 - 117
backend/tracim_backend/models/applications.py Zobrazit soubor

1
-# coding=utf-8
2
-import typing
3
-
4
-
5
-class Application(object):
6
-    """
7
-    Application class with data needed for frontend
8
-    """
9
-    def __init__(
10
-            self,
11
-            label: str,
12
-            slug: str,
13
-            fa_icon: str,
14
-            hexcolor: str,
15
-            is_active: bool,
16
-            config: typing.Dict[str, str],
17
-            main_route: str,
18
-    ) -> None:
19
-        """
20
-        @param label: public label of application
21
-        @param slug: identifier of application
22
-        @param icon: font awesome icon class
23
-        @param hexcolor: hexa color of application main color
24
-        @param is_active: True if application enable, False if inactive
25
-        @param config: a dict with eventual application config
26
-        @param main_route: the route of the frontend "home" screen of
27
-        the application. For exemple, if you have an application
28
-        called "calendar", the main route will be something
29
-        like /#/workspace/{wid}/calendar.
30
-        """
31
-        self.label = label
32
-        self.slug = slug
33
-        self.fa_icon = fa_icon
34
-        self.hexcolor = hexcolor
35
-        self.is_active = is_active
36
-        self.config = config
37
-        self.main_route = main_route
38
-
39
-    # TODO - G.M - 2018-08-07 - Refactor slug coherence issue like this one.
40
-    # we probably should not have 2 kind of slug
41
-    @property
42
-    def minislug(self):
43
-        return self.slug.replace('contents/', '')
44
-
45
-
46
-# default apps
47
-calendar = Application(
48
-    label='Calendar',
49
-    slug='calendar',
50
-    fa_icon='calendar',
51
-    hexcolor='#757575',
52
-    is_active=True,
53
-    config={},
54
-    main_route='/#/workspaces/{workspace_id}/calendar',
55
-)
56
-
57
-thread = Application(
58
-    label='Threads',
59
-    slug='contents/thread',
60
-    fa_icon='comments-o',
61
-    hexcolor='#ad4cf9',
62
-    is_active=True,
63
-    config={},
64
-    main_route='/#/workspaces/{workspace_id}/contents?type=thread',
65
-
66
-)
67
-
68
-folder = Application(
69
-    label='Folder',
70
-    slug='contents/folder',
71
-    fa_icon='folder-open-o',
72
-    hexcolor='#252525',
73
-    is_active=True,
74
-    config={},
75
-    main_route='',
76
-)
77
-
78
-_file = Application(
79
-    label='Files',
80
-    slug='contents/file',
81
-    fa_icon='paperclip',
82
-    hexcolor='#FF9900',
83
-    is_active=True,
84
-    config={},
85
-    main_route='/#/workspaces/{workspace_id}/contents?type=file',
86
-)
87
-
88
-markdownpluspage = Application(
89
-    label='Markdown Plus Documents',  # TODO - G.M - 24-05-2018 - Check label
90
-    slug='contents/markdownpluspage',
91
-    fa_icon='file-code-o',
92
-    hexcolor='#f12d2d',
93
-    is_active=True,
94
-    config={},
95
-    main_route='/#/workspaces/{workspace_id}/contents?type=markdownpluspage',
96
-)
97
-
98
-html_documents = Application(
99
-    label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
100
-    slug='contents/html-document',
101
-    fa_icon='file-text-o',
102
-    hexcolor='#3f52e3',
103
-    is_active=True,
104
-    config={},
105
-    main_route='/#/workspaces/{workspace_id}/contents?type=html-document',
106
-)
107
-# TODO - G.M - 08-06-2018 - This is hardcoded lists of app, make this dynamic.
108
-# List of applications
109
-applications = [
110
-    html_documents,
111
-    # TODO - G.M - 2018-08-02 - Restore markdownpage app
112
-    # markdownpluspage,
113
-    _file,
114
-    thread,
115
-    folder,
116
-    # calendar,
117
-]

+ 8 - 4
backend/tracim_backend/models/context_models.py Zobrazit soubor

7
 from sqlalchemy.orm import Session
7
 from sqlalchemy.orm import Session
8
 from tracim_backend.config import CFG
8
 from tracim_backend.config import CFG
9
 from tracim_backend.config import PreviewDim
9
 from tracim_backend.config import PreviewDim
10
+from tracim_backend.extensions import app_list
11
+from tracim_backend.lib.core.application import ApplicationApi
10
 from tracim_backend.lib.utils.utils import get_root_frontend_url
12
 from tracim_backend.lib.utils.utils import get_root_frontend_url
11
 from tracim_backend.lib.utils.utils import password_generator
13
 from tracim_backend.lib.utils.utils import password_generator
12
 from tracim_backend.lib.utils.utils import CONTENT_FRONTEND_URL_SCHEMA
14
 from tracim_backend.lib.utils.utils import CONTENT_FRONTEND_URL_SCHEMA
19
 from tracim_backend.models.data import Workspace
21
 from tracim_backend.models.data import Workspace
20
 from tracim_backend.models.data import UserRoleInWorkspace
22
 from tracim_backend.models.data import UserRoleInWorkspace
21
 from tracim_backend.models.roles import WorkspaceRoles
23
 from tracim_backend.models.roles import WorkspaceRoles
22
-from tracim_backend.models.workspace_menu_entries import default_workspace_menu_entry  # nopep8
23
-from tracim_backend.models.workspace_menu_entries import WorkspaceMenuEntry
24
-from tracim_backend.models.contents import CONTENT_TYPES
24
+from tracim_backend.app_models.workspace_menu_entries import WorkspaceMenuEntry
25
+from tracim_backend.app_models.contents import CONTENT_TYPES
25
 
26
 
26
 
27
 
27
 class PreviewAllowedDim(object):
28
 class PreviewAllowedDim(object):
493
         # order to not use hardcoded list
494
         # order to not use hardcoded list
494
         # list should be able to change (depending on activated/disabled
495
         # list should be able to change (depending on activated/disabled
495
         # apps)
496
         # apps)
496
-        return default_workspace_menu_entry(self.workspace)
497
+        app_api = ApplicationApi(
498
+            app_list
499
+        )
500
+        return app_api.get_default_workspace_menu_entry(self.workspace)
497
 
501
 
498
     @property
502
     @property
499
     def frontend_url(self):
503
     def frontend_url(self):

+ 5 - 5
backend/tracim_backend/models/data.py Zobrazit soubor

87
 
87
 
88
     def get_allowed_content_types(self):
88
     def get_allowed_content_types(self):
89
         # @see Content.get_allowed_content_types()
89
         # @see Content.get_allowed_content_types()
90
-        return CONTENT_TYPES.extended_endpoint_allowed_types_slug()
90
+        return CONTENT_TYPES.endpoint_allowed_types_slug()
91
 
91
 
92
     def get_valid_children(
92
     def get_valid_children(
93
             self,
93
             self,
282
                 ]
282
                 ]
283
 
283
 
284
 
284
 
285
-from tracim_backend.models.contents import CONTENT_STATUS
286
-from tracim_backend.models.contents import ContentStatus
287
-from tracim_backend.models.contents import CONTENT_TYPES
285
+from tracim_backend.app_models.contents import CONTENT_STATUS
286
+from tracim_backend.app_models.contents import ContentStatus
287
+from tracim_backend.app_models.contents import CONTENT_TYPES
288
 # TODO - G.M - 30-05-2018 - Drop this old code when whe are sure nothing
288
 # TODO - G.M - 30-05-2018 - Drop this old code when whe are sure nothing
289
 # is lost .
289
 # is lost .
290
 
290
 
552
                 for content_slug, value in properties['allowed_content'].items():  # nopep8
552
                 for content_slug, value in properties['allowed_content'].items():  # nopep8
553
                     if not isinstance(value, bool):
553
                     if not isinstance(value, bool):
554
                         return False
554
                         return False
555
-                    if not content_slug in CONTENT_TYPES.extended_endpoint_allowed_types_slug():  # nopep8
555
+                    if not content_slug in CONTENT_TYPES.endpoint_allowed_types_slug():  # nopep8
556
                         return False
556
                         return False
557
             if 'origin' in properties.keys():
557
             if 'origin' in properties.keys():
558
                 pass
558
                 pass

+ 0 - 71
backend/tracim_backend/models/workspace_menu_entries.py Zobrazit soubor

1
-# coding=utf-8
2
-import typing
3
-from copy import copy
4
-
5
-from tracim_backend.models.applications import applications
6
-from tracim_backend.models.data import Workspace
7
-
8
-
9
-class WorkspaceMenuEntry(object):
10
-    """
11
-    Application class with data needed for frontend
12
-    """
13
-    def __init__(
14
-            self,
15
-            label: str,
16
-            slug: str,
17
-            fa_icon: str,
18
-            hexcolor: str,
19
-            route: str,
20
-    ) -> None:
21
-        self.slug = slug
22
-        self.label = label
23
-        self.route = route
24
-        self.hexcolor = hexcolor
25
-        self.fa_icon = fa_icon
26
-
27
-dashboard_menu_entry = WorkspaceMenuEntry(
28
-  slug='dashboard',
29
-  label='Dashboard',
30
-  route='/#/workspaces/{workspace_id}/dashboard',
31
-  hexcolor='#252525',
32
-  fa_icon="signal",
33
-)
34
-all_content_menu_entry = WorkspaceMenuEntry(
35
-  slug="contents/all",
36
-  label="All Contents",
37
-  route="/#/workspaces/{workspace_id}/contents",
38
-  hexcolor="#fdfdfd",
39
-  fa_icon="th",
40
-)
41
-
42
-# TODO - G.M - 08-06-2018 - This is hardcoded default menu entry,
43
-#  of app, make this dynamic (and loaded from application system)
44
-def default_workspace_menu_entry(
45
-    workspace: Workspace,
46
-)-> typing.List[WorkspaceMenuEntry]:
47
-    """
48
-    Get default menu entry for a workspace
49
-    """
50
-    menu_entries = [
51
-        copy(dashboard_menu_entry),
52
-        copy(all_content_menu_entry),
53
-    ]
54
-    for app in applications:
55
-        if app.main_route:
56
-            new_entry = WorkspaceMenuEntry(
57
-                slug=app.slug,
58
-                label=app.label,
59
-                hexcolor=app.hexcolor,
60
-                fa_icon=app.fa_icon,
61
-                route=app.main_route
62
-            )
63
-            menu_entries.append(new_entry)
64
-
65
-    for entry in menu_entries:
66
-        entry.route = entry.route.replace(
67
-            '{workspace_id}',
68
-            str(workspace.workspace_id)
69
-        )
70
-
71
-    return menu_entries

+ 1 - 1
backend/tracim_backend/tests/__init__.py Zobrazit soubor

14
 from tracim_backend.models import DeclarativeBase
14
 from tracim_backend.models import DeclarativeBase
15
 from tracim_backend.models import get_session_factory
15
 from tracim_backend.models import get_session_factory
16
 from tracim_backend.models import get_tm_session
16
 from tracim_backend.models import get_tm_session
17
-from tracim_backend.models.contents import CONTENT_TYPES
17
+from tracim_backend.app_models.contents import CONTENT_TYPES
18
 from tracim_backend.models.data import Workspace
18
 from tracim_backend.models.data import Workspace
19
 from tracim_backend.models.data import ContentRevisionRO
19
 from tracim_backend.models.data import ContentRevisionRO
20
 from tracim_backend.models.data import Content
20
 from tracim_backend.models.data import Content

+ 1 - 1
backend/tracim_backend/tests/functional/test_contents.py Zobrazit soubor

5
 from tracim_backend.lib.core.content import ContentApi
5
 from tracim_backend.lib.core.content import ContentApi
6
 from tracim_backend.lib.core.workspace import WorkspaceApi
6
 from tracim_backend.lib.core.workspace import WorkspaceApi
7
 from tracim_backend.models import get_tm_session
7
 from tracim_backend.models import get_tm_session
8
-from tracim_backend.models.contents import CONTENT_TYPES
8
+from tracim_backend.app_models.contents import CONTENT_TYPES
9
 from tracim_backend.models.revision_protection import new_revision
9
 from tracim_backend.models.revision_protection import new_revision
10
 import io
10
 import io
11
 
11
 

+ 1 - 1
backend/tracim_backend/tests/functional/test_mail_notification.py Zobrazit soubor

11
 from tracim_backend.fixtures.content import Content as ContentFixture
11
 from tracim_backend.fixtures.content import Content as ContentFixture
12
 from tracim_backend.lib.utils.utils import get_redis_connection
12
 from tracim_backend.lib.utils.utils import get_redis_connection
13
 from tracim_backend.lib.utils.utils import get_rq_queue
13
 from tracim_backend.lib.utils.utils import get_rq_queue
14
-from tracim_backend.models.contents import CONTENT_TYPES
14
+from tracim_backend.app_models.contents import CONTENT_TYPES
15
 
15
 
16
 from tracim_backend.lib.core.content import ContentApi
16
 from tracim_backend.lib.core.content import ContentApi
17
 from tracim_backend.lib.core.user import UserApi
17
 from tracim_backend.lib.core.user import UserApi

+ 10 - 2
backend/tracim_backend/tests/functional/test_system.py Zobrazit soubor

1
 # coding=utf-8
1
 # coding=utf-8
2
-from tracim_backend.models.contents import CONTENT_TYPES
2
+import transaction
3
+from tracim_backend.extensions import app_list
4
+from tracim_backend.lib.core.application import ApplicationApi
5
+from tracim_backend.models import get_tm_session
6
+from tracim_backend.app_models.contents import CONTENT_TYPES
3
 from tracim_backend.tests import FunctionalTest
7
 from tracim_backend.tests import FunctionalTest
4
-from tracim_backend.models.applications import applications
5
 
8
 
6
 """
9
 """
7
 Tests for /api/v2/system subpath endpoints.
10
 Tests for /api/v2/system subpath endpoints.
26
         )
29
         )
27
         res = self.testapp.get('/api/v2/system/applications', status=200)
30
         res = self.testapp.get('/api/v2/system/applications', status=200)
28
         res = res.json_body
31
         res = res.json_body
32
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
33
+        app_api = ApplicationApi(
34
+            app_list=app_list,
35
+        )
36
+        applications = app_api.get_all()
29
         assert len(res) == len(applications)
37
         assert len(res) == len(applications)
30
         for counter, application in enumerate(applications):
38
         for counter, application in enumerate(applications):
31
             assert res[counter]['label'] == application.label
39
             assert res[counter]['label'] == application.label

+ 26 - 39
backend/tracim_backend/tests/functional/test_user.py Zobrazit soubor

8
 import transaction
8
 import transaction
9
 
9
 
10
 from tracim_backend import models
10
 from tracim_backend import models
11
+from tracim_backend.extensions import app_list
12
+from tracim_backend.lib.core.application import ApplicationApi
11
 from tracim_backend.lib.core.content import ContentApi
13
 from tracim_backend.lib.core.content import ContentApi
12
 from tracim_backend.lib.core.user import UserApi
14
 from tracim_backend.lib.core.user import UserApi
13
 from tracim_backend.lib.core.group import GroupApi
15
 from tracim_backend.lib.core.group import GroupApi
14
 from tracim_backend.lib.core.userworkspace import RoleApi
16
 from tracim_backend.lib.core.userworkspace import RoleApi
15
 from tracim_backend.lib.core.workspace import WorkspaceApi
17
 from tracim_backend.lib.core.workspace import WorkspaceApi
16
 from tracim_backend.models import get_tm_session
18
 from tracim_backend.models import get_tm_session
17
-from tracim_backend.models.contents import CONTENT_TYPES
19
+from tracim_backend.app_models.contents import CONTENT_TYPES
18
 from tracim_backend.models.data import UserRoleInWorkspace
20
 from tracim_backend.models.data import UserRoleInWorkspace
19
 from tracim_backend.models.revision_protection import new_revision
21
 from tracim_backend.models.revision_protection import new_revision
20
 from tracim_backend.tests import FunctionalTest
22
 from tracim_backend.tests import FunctionalTest
2370
         """
2372
         """
2371
         Check obtain all workspaces reachables for user with user auth.
2373
         Check obtain all workspaces reachables for user with user auth.
2372
         """
2374
         """
2375
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2376
+        admin = dbsession.query(models.User) \
2377
+            .filter(models.User.email == 'admin@admin.admin') \
2378
+            .one()
2379
+
2380
+        workspace_api = WorkspaceApi(
2381
+            session=dbsession,
2382
+            current_user=admin,
2383
+            config=self.app_config,
2384
+        )
2385
+        workspace = workspace_api.get_one(1)
2386
+        app_api = ApplicationApi(
2387
+            app_list
2388
+        )
2389
+
2390
+        default_sidebar_entry = app_api.get_default_workspace_menu_entry(workspace=workspace)  # nope8
2373
         self.testapp.authorization = (
2391
         self.testapp.authorization = (
2374
             'Basic',
2392
             'Basic',
2375
             (
2393
             (
2384
         assert workspace['label'] == 'Business'
2402
         assert workspace['label'] == 'Business'
2385
         assert workspace['slug'] == 'business'
2403
         assert workspace['slug'] == 'business'
2386
         assert workspace['is_deleted'] is False
2404
         assert workspace['is_deleted'] is False
2387
-        assert len(workspace['sidebar_entries']) == 5
2388
-
2389
-        # TODO - G.M - 2018-08-02 - Better test for sidebar entry, make it
2390
-        # not fixed on active application/content-file
2391
-        sidebar_entry = workspace['sidebar_entries'][0]
2392
-        assert sidebar_entry['slug'] == 'dashboard'
2393
-        assert sidebar_entry['label'] == 'Dashboard'
2394
-        assert sidebar_entry['route'] == '/#/workspaces/1/dashboard'  # nopep8
2395
-        assert sidebar_entry['hexcolor'] == "#252525"
2396
-        assert sidebar_entry['fa_icon'] == "signal"
2397
-
2398
-        sidebar_entry = workspace['sidebar_entries'][1]
2399
-        assert sidebar_entry['slug'] == 'contents/all'
2400
-        assert sidebar_entry['label'] == 'All Contents'
2401
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents"  # nopep8
2402
-        assert sidebar_entry['hexcolor'] == "#fdfdfd"
2403
-        assert sidebar_entry['fa_icon'] == "th"
2404
-
2405
-        sidebar_entry = workspace['sidebar_entries'][2]
2406
-        assert sidebar_entry['slug'] == 'contents/html-document'
2407
-        assert sidebar_entry['label'] == 'Text Documents'
2408
-        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=html-document'  # nopep8
2409
-        assert sidebar_entry['hexcolor'] == "#3f52e3"
2410
-        assert sidebar_entry['fa_icon'] == "file-text-o"
2411
-
2412
-        sidebar_entry = workspace['sidebar_entries'][3]
2413
-        assert sidebar_entry['slug'] == 'contents/file'
2414
-        assert sidebar_entry['label'] == 'Files'
2415
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=file"  # nopep8
2416
-        assert sidebar_entry['hexcolor'] == "#FF9900"
2417
-        assert sidebar_entry['fa_icon'] == "paperclip"
2418
-
2419
-        sidebar_entry = workspace['sidebar_entries'][4]
2420
-        assert sidebar_entry['slug'] == 'contents/thread'
2421
-        assert sidebar_entry['label'] == 'Threads'
2422
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=thread"  # nopep8
2423
-        assert sidebar_entry['hexcolor'] == "#ad4cf9"
2424
-        assert sidebar_entry['fa_icon'] == "comments-o"
2425
 
2405
 
2406
+        assert len(workspace['sidebar_entries']) == len(default_sidebar_entry)
2407
+        for counter, sidebar_entry in enumerate(default_sidebar_entry):
2408
+            workspace['sidebar_entries'][counter]['slug'] = sidebar_entry.slug
2409
+            workspace['sidebar_entries'][counter]['label'] = sidebar_entry.label
2410
+            workspace['sidebar_entries'][counter]['route'] = sidebar_entry.route
2411
+            workspace['sidebar_entries'][counter]['hexcolor'] = sidebar_entry.hexcolor  # nopep8
2412
+            workspace['sidebar_entries'][counter]['fa_icon'] = sidebar_entry.fa_icon  # nopep8
2426
 
2413
 
2427
     def test_api__get_user_workspaces__err_403__unallowed_user(self):
2414
     def test_api__get_user_workspaces__err_403__unallowed_user(self):
2428
         """
2415
         """

+ 46 - 42
backend/tracim_backend/tests/functional/test_workspaces.py Zobrazit soubor

7
 from depot.io.utils import FileIntent
7
 from depot.io.utils import FileIntent
8
 
8
 
9
 from tracim_backend import models
9
 from tracim_backend import models
10
+from tracim_backend.extensions import app_list
11
+from tracim_backend.lib.core.application import ApplicationApi
10
 from tracim_backend.lib.core.content import ContentApi
12
 from tracim_backend.lib.core.content import ContentApi
11
 from tracim_backend.lib.core.group import GroupApi
13
 from tracim_backend.lib.core.group import GroupApi
12
 from tracim_backend.lib.core.user import UserApi
14
 from tracim_backend.lib.core.user import UserApi
13
 from tracim_backend.lib.core.userworkspace import RoleApi
15
 from tracim_backend.lib.core.userworkspace import RoleApi
14
 from tracim_backend.lib.core.workspace import WorkspaceApi
16
 from tracim_backend.lib.core.workspace import WorkspaceApi
15
 from tracim_backend.models import get_tm_session
17
 from tracim_backend.models import get_tm_session
16
-from tracim_backend.models.contents import CONTENT_TYPES
18
+from tracim_backend.app_models.contents import CONTENT_TYPES
17
 from tracim_backend.models.data import UserRoleInWorkspace
19
 from tracim_backend.models.data import UserRoleInWorkspace
18
 from tracim_backend.tests import FunctionalTest
20
 from tracim_backend.tests import FunctionalTest
19
 from tracim_backend.tests import set_html_document_slug_to_legacy
21
 from tracim_backend.tests import set_html_document_slug_to_legacy
32
         """
34
         """
33
         Check obtain workspace reachable for user.
35
         Check obtain workspace reachable for user.
34
         """
36
         """
37
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
38
+        admin = dbsession.query(models.User) \
39
+            .filter(models.User.email == 'admin@admin.admin') \
40
+            .one()
41
+
42
+        workspace_api = WorkspaceApi(
43
+            session=dbsession,
44
+            current_user=admin,
45
+            config=self.app_config,
46
+        )
47
+        workspace = workspace_api.get_one(1)
48
+        app_api = ApplicationApi(
49
+            app_list
50
+        )
51
+        default_sidebar_entry = app_api.get_default_workspace_menu_entry(workspace=workspace)  # nope8
52
+
35
         self.testapp.authorization = (
53
         self.testapp.authorization = (
36
             'Basic',
54
             'Basic',
37
             (
55
             (
46
         assert workspace['label'] == 'Business'
64
         assert workspace['label'] == 'Business'
47
         assert workspace['description'] == 'All importants documents'
65
         assert workspace['description'] == 'All importants documents'
48
         assert workspace['is_deleted'] is False
66
         assert workspace['is_deleted'] is False
49
-        assert len(workspace['sidebar_entries']) == 5
50
-
51
-        # TODO - G.M - 2018-08-02 - Better test for sidebar entry, make it
52
-        # not fixed on active application/content-file
53
-        sidebar_entry = workspace['sidebar_entries'][0]
54
-        assert sidebar_entry['slug'] == 'dashboard'
55
-        assert sidebar_entry['label'] == 'Dashboard'
56
-        assert sidebar_entry['route'] == '/#/workspaces/1/dashboard'  # nopep8
57
-        assert sidebar_entry['hexcolor'] == "#252525"
58
-        assert sidebar_entry['fa_icon'] == "signal"
59
-
60
-        sidebar_entry = workspace['sidebar_entries'][1]
61
-        assert sidebar_entry['slug'] == 'contents/all'
62
-        assert sidebar_entry['label'] == 'All Contents'
63
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents"  # nopep8
64
-        assert sidebar_entry['hexcolor'] == "#fdfdfd"
65
-        assert sidebar_entry['fa_icon'] == "th"
66
-
67
-        sidebar_entry = workspace['sidebar_entries'][2]
68
-        assert sidebar_entry['slug'] == 'contents/html-document'
69
-        assert sidebar_entry['label'] == 'Text Documents'
70
-        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=html-document'  # nopep8
71
-        assert sidebar_entry['hexcolor'] == "#3f52e3"
72
-        assert sidebar_entry['fa_icon'] == "file-text-o"
73
-
74
-        sidebar_entry = workspace['sidebar_entries'][3]
75
-        assert sidebar_entry['slug'] == 'contents/file'
76
-        assert sidebar_entry['label'] == 'Files'
77
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=file"  # nopep8
78
-        assert sidebar_entry['hexcolor'] == "#FF9900"
79
-        assert sidebar_entry['fa_icon'] == "paperclip"
80
-
81
-        sidebar_entry = workspace['sidebar_entries'][4]
82
-        assert sidebar_entry['slug'] == 'contents/thread'
83
-        assert sidebar_entry['label'] == 'Threads'
84
-        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=thread"  # nopep8
85
-        assert sidebar_entry['hexcolor'] == "#ad4cf9"
86
-        assert sidebar_entry['fa_icon'] == "comments-o"
67
+
68
+        assert len(workspace['sidebar_entries']) == len(default_sidebar_entry)
69
+        for counter, sidebar_entry in enumerate(default_sidebar_entry):
70
+            workspace['sidebar_entries'][counter]['slug'] = sidebar_entry.slug
71
+            workspace['sidebar_entries'][counter]['label'] = sidebar_entry.label
72
+            workspace['sidebar_entries'][counter]['route'] = sidebar_entry.route
73
+            workspace['sidebar_entries'][counter]['hexcolor'] = sidebar_entry.hexcolor  # nopep8
74
+            workspace['sidebar_entries'][counter]['fa_icon'] = sidebar_entry.fa_icon  # nopep8
87
 
75
 
88
     def test_api__update_workspace__ok_200__nominal_case(self) -> None:
76
     def test_api__update_workspace__ok_200__nominal_case(self) -> None:
89
         """
77
         """
90
         Test update workspace
78
         Test update workspace
91
         """
79
         """
80
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
81
+        admin = dbsession.query(models.User) \
82
+            .filter(models.User.email == 'admin@admin.admin') \
83
+            .one()
84
+
85
+        workspace_api = WorkspaceApi(
86
+            session=dbsession,
87
+            current_user=admin,
88
+            config=self.app_config,
89
+        )
90
+        workspace = workspace_api.get_one(1)
91
+        app_api = ApplicationApi(
92
+            app_list
93
+        )
94
+        default_sidebar_entry = app_api.get_default_workspace_menu_entry(workspace=workspace)  # nope8
95
+
92
         self.testapp.authorization = (
96
         self.testapp.authorization = (
93
             'Basic',
97
             'Basic',
94
             (
98
             (
111
         assert workspace['slug'] == 'business'
115
         assert workspace['slug'] == 'business'
112
         assert workspace['label'] == 'Business'
116
         assert workspace['label'] == 'Business'
113
         assert workspace['description'] == 'All importants documents'
117
         assert workspace['description'] == 'All importants documents'
118
+        assert len(workspace['sidebar_entries']) == len(default_sidebar_entry)
114
         assert workspace['is_deleted'] is False
119
         assert workspace['is_deleted'] is False
115
-        assert len(workspace['sidebar_entries']) == 5
116
 
120
 
117
         # modify workspace
121
         # modify workspace
118
         res = self.testapp.put_json(
122
         res = self.testapp.put_json(
126
         assert workspace['slug'] == 'superworkspace'
130
         assert workspace['slug'] == 'superworkspace'
127
         assert workspace['label'] == 'superworkspace'
131
         assert workspace['label'] == 'superworkspace'
128
         assert workspace['description'] == 'mysuperdescription'
132
         assert workspace['description'] == 'mysuperdescription'
133
+        assert len(workspace['sidebar_entries']) == len(default_sidebar_entry)
129
         assert workspace['is_deleted'] is False
134
         assert workspace['is_deleted'] is False
130
-        assert len(workspace['sidebar_entries']) == 5
131
 
135
 
132
         # after
136
         # after
133
         res = self.testapp.get(
137
         res = self.testapp.get(
140
         assert workspace['slug'] == 'superworkspace'
144
         assert workspace['slug'] == 'superworkspace'
141
         assert workspace['label'] == 'superworkspace'
145
         assert workspace['label'] == 'superworkspace'
142
         assert workspace['description'] == 'mysuperdescription'
146
         assert workspace['description'] == 'mysuperdescription'
147
+        assert len(workspace['sidebar_entries']) == len(default_sidebar_entry)
143
         assert workspace['is_deleted'] is False
148
         assert workspace['is_deleted'] is False
144
-        assert len(workspace['sidebar_entries']) == 5
145
 
149
 
146
     def test_api__update_workspace__err_400__empty_label(self) -> None:
150
     def test_api__update_workspace__err_400__empty_label(self) -> None:
147
         """
151
         """

+ 1 - 1
backend/tracim_backend/tests/library/test_content_api.py Zobrazit soubor

16
 from tracim_backend.lib.core.workspace import RoleApi
16
 from tracim_backend.lib.core.workspace import RoleApi
17
 # TODO - G.M - 28-03-2018 - [WorkspaceApi] Re-enable WorkspaceApi
17
 # TODO - G.M - 28-03-2018 - [WorkspaceApi] Re-enable WorkspaceApi
18
 from tracim_backend.lib.core.workspace import WorkspaceApi
18
 from tracim_backend.lib.core.workspace import WorkspaceApi
19
-from tracim_backend.models.contents import CONTENT_TYPES
19
+from tracim_backend.app_models.contents import CONTENT_TYPES
20
 from tracim_backend.models.revision_protection import new_revision
20
 from tracim_backend.models.revision_protection import new_revision
21
 from tracim_backend.models.auth import User
21
 from tracim_backend.models.auth import User
22
 from tracim_backend.models.auth import Group
22
 from tracim_backend.models.auth import Group

+ 3 - 10
backend/tracim_backend/tests/library/test_webdav.py Zobrazit soubor

22
 
22
 
23
 class TestWebdavFactory(StandardTest):
23
 class TestWebdavFactory(StandardTest):
24
 
24
 
25
+    config_section = 'webdav_test'
26
+
25
     def test_unit__initConfig__ok__nominal_case(self):
27
     def test_unit__initConfig__ok__nominal_case(self):
26
         """
28
         """
27
         Check if config is correctly modify for wsgidav using mocked
29
         Check if config is correctly modify for wsgidav using mocked
28
         wsgidav and tracim conf (as dict)
30
         wsgidav and tracim conf (as dict)
29
         :return:
31
         :return:
30
         """
32
         """
31
-        tracim_settings = {
32
-            'website.base_url': 'http://localhost:6543',
33
-            'sqlalchemy.url': 'sqlite:///:memory:',
34
-            'user.auth_token.validity': '604800',
35
-            'depot_storage_dir': '/tmp/test/depot',
36
-            'depot_storage_name': 'test',
37
-            'preview_cache_dir': '/tmp/test/preview_cache',
38
-            'wsgidav.config_path': 'development.ini'
39
-
40
-        }
33
+        tracim_settings = self.settings
41
         wsgidav_setting = DEFAULT_CONFIG.copy()
34
         wsgidav_setting = DEFAULT_CONFIG.copy()
42
         wsgidav_setting.update(
35
         wsgidav_setting.update(
43
             {
36
             {

+ 1 - 1
backend/tracim_backend/tests/models/test_content.py Zobrazit soubor

15
 from tracim_backend.models import User
15
 from tracim_backend.models import User
16
 from tracim_backend.models.data import ActionDescription
16
 from tracim_backend.models.data import ActionDescription
17
 from tracim_backend.models.data import ContentRevisionRO
17
 from tracim_backend.models.data import ContentRevisionRO
18
-from tracim_backend.models.contents import CONTENT_TYPES
18
+from tracim_backend.app_models.contents import CONTENT_TYPES
19
 from tracim_backend.models.data import Workspace
19
 from tracim_backend.models.data import Workspace
20
 from tracim_backend.tests import StandardTest
20
 from tracim_backend.tests import StandardTest
21
 
21
 

+ 1 - 1
backend/tracim_backend/tests/models/test_content_revision.py Zobrazit soubor

5
 
5
 
6
 from tracim_backend.models import ContentRevisionRO
6
 from tracim_backend.models import ContentRevisionRO
7
 from tracim_backend.models import User
7
 from tracim_backend.models import User
8
-from tracim_backend.models.contents import CONTENT_TYPES
8
+from tracim_backend.app_models.contents import CONTENT_TYPES
9
 from tracim_backend.tests import DefaultTest
9
 from tracim_backend.tests import DefaultTest
10
 from tracim_backend.tests import eq_
10
 from tracim_backend.tests import eq_
11
 
11
 

+ 2 - 2
backend/tracim_backend/views/contents_api/comment_controller.py Zobrazit soubor

7
 except ImportError:
7
 except ImportError:
8
     from http import client as HTTPStatus
8
     from http import client as HTTPStatus
9
 
9
 
10
-from tracim_backend import TracimRequest
10
+from tracim_backend.lib.utils.request import TracimRequest
11
 from tracim_backend.extensions import hapic
11
 from tracim_backend.extensions import hapic
12
 from tracim_backend.lib.core.content import ContentApi
12
 from tracim_backend.lib.core.content import ContentApi
13
 from tracim_backend.lib.core.workspace import WorkspaceApi
13
 from tracim_backend.lib.core.workspace import WorkspaceApi
20
 from tracim_backend.views.core_api.schemas import WorkspaceAndContentIdPathSchema
20
 from tracim_backend.views.core_api.schemas import WorkspaceAndContentIdPathSchema
21
 from tracim_backend.views.core_api.schemas import NoContentSchema
21
 from tracim_backend.views.core_api.schemas import NoContentSchema
22
 from tracim_backend.exceptions import EmptyCommentContentNotAllowed
22
 from tracim_backend.exceptions import EmptyCommentContentNotAllowed
23
-from tracim_backend.models.contents import CONTENT_TYPES
23
+from tracim_backend.app_models.contents import CONTENT_TYPES
24
 from tracim_backend.models.revision_protection import new_revision
24
 from tracim_backend.models.revision_protection import new_revision
25
 from tracim_backend.models.data import UserRoleInWorkspace
25
 from tracim_backend.models.data import UserRoleInWorkspace
26
 
26
 

+ 17 - 17
backend/tracim_backend/views/contents_api/file_controller.py Zobrazit soubor

12
 except ImportError:
12
 except ImportError:
13
     from http import client as HTTPStatus
13
     from http import client as HTTPStatus
14
 
14
 
15
-from tracim_backend import TracimRequest
15
+from tracim_backend.lib.utils.request import TracimRequest
16
 from tracim_backend.extensions import hapic
16
 from tracim_backend.extensions import hapic
17
 from tracim_backend.lib.core.content import ContentApi
17
 from tracim_backend.lib.core.content import ContentApi
18
 from tracim_backend.views.controllers import Controller
18
 from tracim_backend.views.controllers import Controller
32
 from tracim_backend.models.data import UserRoleInWorkspace
32
 from tracim_backend.models.data import UserRoleInWorkspace
33
 from tracim_backend.models.context_models import ContentInContext
33
 from tracim_backend.models.context_models import ContentInContext
34
 from tracim_backend.models.context_models import RevisionInContext
34
 from tracim_backend.models.context_models import RevisionInContext
35
-from tracim_backend.models.contents import CONTENT_TYPES
36
-from tracim_backend.models.contents import file_type
35
+from tracim_backend.app_models.contents import CONTENT_TYPES
36
+from tracim_backend.app_models.contents import FILE_TYPE
37
 from tracim_backend.models.revision_protection import new_revision
37
 from tracim_backend.models.revision_protection import new_revision
38
 from tracim_backend.exceptions import EmptyLabelNotAllowed
38
 from tracim_backend.exceptions import EmptyLabelNotAllowed
39
 from tracim_backend.exceptions import PageOfPreviewNotFound
39
 from tracim_backend.exceptions import PageOfPreviewNotFound
50
     # File data
50
     # File data
51
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
51
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
52
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
52
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
53
-    @require_content_types([file_type])
53
+    @require_content_types([FILE_TYPE])
54
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
54
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
55
     # TODO - G.M - 2018-07-24 - Use hapic for input file
55
     # TODO - G.M - 2018-07-24 - Use hapic for input file
56
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
56
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
88
 
88
 
89
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
89
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
90
     @require_workspace_role(UserRoleInWorkspace.READER)
90
     @require_workspace_role(UserRoleInWorkspace.READER)
91
-    @require_content_types([file_type])
91
+    @require_content_types([FILE_TYPE])
92
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
92
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
93
     @hapic.output_file([])
93
     @hapic.output_file([])
94
     def download_file(self, context, request: TracimRequest, hapic_data=None):
94
     def download_file(self, context, request: TracimRequest, hapic_data=None):
115
 
115
 
116
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
116
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
117
     @require_workspace_role(UserRoleInWorkspace.READER)
117
     @require_workspace_role(UserRoleInWorkspace.READER)
118
-    @require_content_types([file_type])
118
+    @require_content_types([FILE_TYPE])
119
     @hapic.input_path(WorkspaceAndContentRevisionIdPathSchema())
119
     @hapic.input_path(WorkspaceAndContentRevisionIdPathSchema())
120
     @hapic.output_file([])
120
     @hapic.output_file([])
121
     def download_revisions_file(self, context, request: TracimRequest, hapic_data=None):  # nopep8
121
     def download_revisions_file(self, context, request: TracimRequest, hapic_data=None):  # nopep8
148
     # pdf
148
     # pdf
149
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
149
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
150
     @require_workspace_role(UserRoleInWorkspace.READER)
150
     @require_workspace_role(UserRoleInWorkspace.READER)
151
-    @require_content_types([file_type])
151
+    @require_content_types([FILE_TYPE])
152
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
152
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
153
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
153
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
154
     @hapic.input_query(PageQuerySchema())
154
     @hapic.input_query(PageQuerySchema())
179
 
179
 
180
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
180
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
181
     @require_workspace_role(UserRoleInWorkspace.READER)
181
     @require_workspace_role(UserRoleInWorkspace.READER)
182
-    @require_content_types([file_type])
182
+    @require_content_types([FILE_TYPE])
183
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
183
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
184
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
184
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
185
     @hapic.output_file([])
185
     @hapic.output_file([])
204
 
204
 
205
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
205
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
206
     @require_workspace_role(UserRoleInWorkspace.READER)
206
     @require_workspace_role(UserRoleInWorkspace.READER)
207
-    @require_content_types([file_type])
207
+    @require_content_types([FILE_TYPE])
208
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
208
     @hapic.handle_exception(UnavailablePreviewType, HTTPStatus.BAD_REQUEST)
209
     @hapic.input_path(WorkspaceAndContentRevisionIdPathSchema())
209
     @hapic.input_path(WorkspaceAndContentRevisionIdPathSchema())
210
     @hapic.input_query(PageQuerySchema())
210
     @hapic.input_query(PageQuerySchema())
239
     # jpg
239
     # jpg
240
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
240
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
241
     @require_workspace_role(UserRoleInWorkspace.READER)
241
     @require_workspace_role(UserRoleInWorkspace.READER)
242
-    @require_content_types([file_type])
242
+    @require_content_types([FILE_TYPE])
243
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
243
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
244
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
244
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
245
     @hapic.input_query(PageQuerySchema())
245
     @hapic.input_query(PageQuerySchema())
272
 
272
 
273
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
273
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
274
     @require_workspace_role(UserRoleInWorkspace.READER)
274
     @require_workspace_role(UserRoleInWorkspace.READER)
275
-    @require_content_types([file_type])
275
+    @require_content_types([FILE_TYPE])
276
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
276
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
277
     @hapic.handle_exception(PreviewDimNotAllowed, HTTPStatus.BAD_REQUEST)
277
     @hapic.handle_exception(PreviewDimNotAllowed, HTTPStatus.BAD_REQUEST)
278
     @hapic.input_query(PageQuerySchema())
278
     @hapic.input_query(PageQuerySchema())
305
 
305
 
306
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
306
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
307
     @require_workspace_role(UserRoleInWorkspace.READER)
307
     @require_workspace_role(UserRoleInWorkspace.READER)
308
-    @require_content_types([file_type])
308
+    @require_content_types([FILE_TYPE])
309
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
309
     @hapic.handle_exception(PageOfPreviewNotFound, HTTPStatus.BAD_REQUEST)
310
     @hapic.handle_exception(PreviewDimNotAllowed, HTTPStatus.BAD_REQUEST)
310
     @hapic.handle_exception(PreviewDimNotAllowed, HTTPStatus.BAD_REQUEST)
311
     @hapic.input_path(RevisionPreviewSizedPathSchema())
311
     @hapic.input_path(RevisionPreviewSizedPathSchema())
342
 
342
 
343
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
343
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
344
     @require_workspace_role(UserRoleInWorkspace.READER)
344
     @require_workspace_role(UserRoleInWorkspace.READER)
345
-    @require_content_types([file_type])
345
+    @require_content_types([FILE_TYPE])
346
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
346
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
347
     @hapic.output_body(AllowedJpgPreviewDimSchema())
347
     @hapic.output_body(AllowedJpgPreviewDimSchema())
348
     def allowed_dim_preview_jpg(self, context, request: TracimRequest, hapic_data=None):  # nopep8
348
     def allowed_dim_preview_jpg(self, context, request: TracimRequest, hapic_data=None):  # nopep8
363
     # File infos
363
     # File infos
364
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
364
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
365
     @require_workspace_role(UserRoleInWorkspace.READER)
365
     @require_workspace_role(UserRoleInWorkspace.READER)
366
-    @require_content_types([file_type])
366
+    @require_content_types([FILE_TYPE])
367
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
367
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
368
     @hapic.output_body(FileContentSchema())
368
     @hapic.output_body(FileContentSchema())
369
     def get_file_infos(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
369
     def get_file_infos(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
387
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
387
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
388
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
388
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
389
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
389
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
390
-    @require_content_types([file_type])
390
+    @require_content_types([FILE_TYPE])
391
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
391
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
392
     @hapic.input_body(FileContentModifySchema())
392
     @hapic.input_body(FileContentModifySchema())
393
     @hapic.output_body(FileContentSchema())
393
     @hapic.output_body(FileContentSchema())
423
 
423
 
424
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
424
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
425
     @require_workspace_role(UserRoleInWorkspace.READER)
425
     @require_workspace_role(UserRoleInWorkspace.READER)
426
-    @require_content_types([file_type])
426
+    @require_content_types([FILE_TYPE])
427
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
427
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
428
     @hapic.output_body(FileRevisionSchema(many=True))
428
     @hapic.output_body(FileRevisionSchema(many=True))
429
     def get_file_revisions(
429
     def get_file_revisions(
456
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
456
     @hapic.with_api_doc(tags=[SWAGGER_TAG__FILE_ENDPOINTS])
457
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
457
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
458
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
458
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
459
-    @require_content_types([file_type])
459
+    @require_content_types([FILE_TYPE])
460
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
460
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
461
     @hapic.input_body(SetContentStatusSchema())
461
     @hapic.input_body(SetContentStatusSchema())
462
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
462
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8

+ 6 - 6
backend/tracim_backend/views/contents_api/folder_controller.py Zobrazit soubor

25
 from tracim_backend.exceptions import EmptyLabelNotAllowed
25
 from tracim_backend.exceptions import EmptyLabelNotAllowed
26
 from tracim_backend.models.context_models import ContentInContext
26
 from tracim_backend.models.context_models import ContentInContext
27
 from tracim_backend.models.context_models import RevisionInContext
27
 from tracim_backend.models.context_models import RevisionInContext
28
-from tracim_backend.models.contents import CONTENT_TYPES
29
-from tracim_backend.models.contents import folder_type
28
+from tracim_backend.app_models.contents import CONTENT_TYPES
29
+from tracim_backend.app_models.contents import FOLDER_TYPE
30
 from tracim_backend.models.revision_protection import new_revision
30
 from tracim_backend.models.revision_protection import new_revision
31
 
31
 
32
 SWAGGER_TAG__Folders_ENDPOINTS = 'Folders'
32
 SWAGGER_TAG__Folders_ENDPOINTS = 'Folders'
36
 
36
 
37
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
37
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
38
     @require_workspace_role(UserRoleInWorkspace.READER)
38
     @require_workspace_role(UserRoleInWorkspace.READER)
39
-    @require_content_types([folder_type])
39
+    @require_content_types([FOLDER_TYPE])
40
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
40
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
41
     @hapic.output_body(TextBasedContentSchema())
41
     @hapic.output_body(TextBasedContentSchema())
42
     def get_folder(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
42
     def get_folder(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
60
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
60
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
61
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
61
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
-    @require_content_types([folder_type])
63
+    @require_content_types([FOLDER_TYPE])
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
65
     @hapic.input_body(FolderContentModifySchema())
65
     @hapic.input_body(FolderContentModifySchema())
66
     @hapic.output_body(TextBasedContentSchema())
66
     @hapic.output_body(TextBasedContentSchema())
100
 
100
 
101
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
101
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
102
     @require_workspace_role(UserRoleInWorkspace.READER)
102
     @require_workspace_role(UserRoleInWorkspace.READER)
103
-    @require_content_types([folder_type])
103
+    @require_content_types([FOLDER_TYPE])
104
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
104
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
105
     @hapic.output_body(TextBasedRevisionSchema(many=True))
105
     @hapic.output_body(TextBasedRevisionSchema(many=True))
106
     def get_folder_revisions(
106
     def get_folder_revisions(
132
 
132
 
133
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
133
     @hapic.with_api_doc(tags=[SWAGGER_TAG__Folders_ENDPOINTS])
134
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
134
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
135
-    @require_content_types([folder_type])
135
+    @require_content_types([FOLDER_TYPE])
136
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
136
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
137
     @hapic.input_body(SetContentStatusSchema())
137
     @hapic.input_body(SetContentStatusSchema())
138
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
138
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8

+ 7 - 7
backend/tracim_backend/views/contents_api/html_document_controller.py Zobrazit soubor

11
 except ImportError:
11
 except ImportError:
12
     from http import client as HTTPStatus
12
     from http import client as HTTPStatus
13
 
13
 
14
-from tracim_backend import TracimRequest
14
+from tracim_backend.lib.utils.request import TracimRequest
15
 from tracim_backend.extensions import hapic
15
 from tracim_backend.extensions import hapic
16
 from tracim_backend.lib.core.content import ContentApi
16
 from tracim_backend.lib.core.content import ContentApi
17
 from tracim_backend.views.controllers import Controller
17
 from tracim_backend.views.controllers import Controller
26
 from tracim_backend.exceptions import EmptyLabelNotAllowed
26
 from tracim_backend.exceptions import EmptyLabelNotAllowed
27
 from tracim_backend.models.context_models import ContentInContext
27
 from tracim_backend.models.context_models import ContentInContext
28
 from tracim_backend.models.context_models import RevisionInContext
28
 from tracim_backend.models.context_models import RevisionInContext
29
-from tracim_backend.models.contents import CONTENT_TYPES
30
-from tracim_backend.models.contents import html_documents_type
29
+from tracim_backend.app_models.contents import CONTENT_TYPES
30
+from tracim_backend.app_models.contents import HTML_DOCUMENTS_TYPE
31
 from tracim_backend.models.revision_protection import new_revision
31
 from tracim_backend.models.revision_protection import new_revision
32
 
32
 
33
 SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS = 'HTML documents'
33
 SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS = 'HTML documents'
37
 
37
 
38
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
38
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
39
     @require_workspace_role(UserRoleInWorkspace.READER)
39
     @require_workspace_role(UserRoleInWorkspace.READER)
40
-    @require_content_types([html_documents_type])
40
+    @require_content_types([HTML_DOCUMENTS_TYPE])
41
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
41
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
42
     @hapic.output_body(TextBasedContentSchema())
42
     @hapic.output_body(TextBasedContentSchema())
43
     def get_html_document(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
43
     def get_html_document(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
61
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
61
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
62
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
62
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
63
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
64
-    @require_content_types([html_documents_type])
64
+    @require_content_types([HTML_DOCUMENTS_TYPE])
65
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
65
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
66
     @hapic.input_body(TextBasedContentModifySchema())
66
     @hapic.input_body(TextBasedContentModifySchema())
67
     @hapic.output_body(TextBasedContentSchema())
67
     @hapic.output_body(TextBasedContentSchema())
97
 
97
 
98
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
98
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
99
     @require_workspace_role(UserRoleInWorkspace.READER)
99
     @require_workspace_role(UserRoleInWorkspace.READER)
100
-    @require_content_types([html_documents_type])
100
+    @require_content_types([HTML_DOCUMENTS_TYPE])
101
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
101
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
102
     @hapic.output_body(TextBasedRevisionSchema(many=True))
102
     @hapic.output_body(TextBasedRevisionSchema(many=True))
103
     def get_html_document_revisions(
103
     def get_html_document_revisions(
129
 
129
 
130
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
130
     @hapic.with_api_doc(tags=[SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS])
131
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
131
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
132
-    @require_content_types([html_documents_type])
132
+    @require_content_types([HTML_DOCUMENTS_TYPE])
133
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
133
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
134
     @hapic.input_body(SetContentStatusSchema())
134
     @hapic.input_body(SetContentStatusSchema())
135
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
135
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8

+ 7 - 7
backend/tracim_backend/views/contents_api/threads_controller.py Zobrazit soubor

10
 except ImportError:
10
 except ImportError:
11
     from http import client as HTTPStatus
11
     from http import client as HTTPStatus
12
 
12
 
13
-from tracim_backend import TracimRequest
13
+from tracim_backend.lib.utils.request import TracimRequest
14
 from tracim_backend.extensions import hapic
14
 from tracim_backend.extensions import hapic
15
 from tracim_backend.lib.core.content import ContentApi
15
 from tracim_backend.lib.core.content import ContentApi
16
 from tracim_backend.views.controllers import Controller
16
 from tracim_backend.views.controllers import Controller
25
 from tracim_backend.exceptions import EmptyLabelNotAllowed
25
 from tracim_backend.exceptions import EmptyLabelNotAllowed
26
 from tracim_backend.models.context_models import ContentInContext
26
 from tracim_backend.models.context_models import ContentInContext
27
 from tracim_backend.models.context_models import RevisionInContext
27
 from tracim_backend.models.context_models import RevisionInContext
28
-from tracim_backend.models.contents import CONTENT_TYPES
29
-from tracim_backend.models.contents import thread_type
28
+from tracim_backend.app_models.contents import CONTENT_TYPES
29
+from tracim_backend.app_models.contents import THREAD_TYPE
30
 from tracim_backend.models.revision_protection import new_revision
30
 from tracim_backend.models.revision_protection import new_revision
31
 
31
 
32
 SWAGGER_TAG__THREAD_ENDPOINTS = 'Threads'
32
 SWAGGER_TAG__THREAD_ENDPOINTS = 'Threads'
36
 
36
 
37
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
37
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
38
     @require_workspace_role(UserRoleInWorkspace.READER)
38
     @require_workspace_role(UserRoleInWorkspace.READER)
39
-    @require_content_types([thread_type])
39
+    @require_content_types([THREAD_TYPE])
40
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
40
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
41
     @hapic.output_body(TextBasedContentSchema())
41
     @hapic.output_body(TextBasedContentSchema())
42
     def get_thread(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
42
     def get_thread(self, context, request: TracimRequest, hapic_data=None) -> ContentInContext:  # nopep8
60
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
60
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
61
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
61
     @hapic.handle_exception(EmptyLabelNotAllowed, HTTPStatus.BAD_REQUEST)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
62
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
63
-    @require_content_types([thread_type])
63
+    @require_content_types([THREAD_TYPE])
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
64
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
65
     @hapic.input_body(TextBasedContentModifySchema())
65
     @hapic.input_body(TextBasedContentModifySchema())
66
     @hapic.output_body(TextBasedContentSchema())
66
     @hapic.output_body(TextBasedContentSchema())
96
 
96
 
97
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
97
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
98
     @require_workspace_role(UserRoleInWorkspace.READER)
98
     @require_workspace_role(UserRoleInWorkspace.READER)
99
-    @require_content_types([thread_type])
99
+    @require_content_types([THREAD_TYPE])
100
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
100
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
101
     @hapic.output_body(TextBasedRevisionSchema(many=True))
101
     @hapic.output_body(TextBasedRevisionSchema(many=True))
102
     def get_thread_revisions(
102
     def get_thread_revisions(
128
 
128
 
129
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
129
     @hapic.with_api_doc(tags=[SWAGGER_TAG__THREAD_ENDPOINTS])
130
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
130
     @require_workspace_role(UserRoleInWorkspace.CONTRIBUTOR)
131
-    @require_content_types([thread_type])
131
+    @require_content_types([THREAD_TYPE])
132
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
132
     @hapic.input_path(WorkspaceAndContentIdPathSchema())
133
     @hapic.input_body(SetContentStatusSchema())
133
     @hapic.input_body(SetContentStatusSchema())
134
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8
134
     @hapic.output_body(NoContentSchema(), default_http_code=HTTPStatus.NO_CONTENT)  # nopep8

+ 12 - 10
backend/tracim_backend/views/core_api/schemas.py Zobrazit soubor

7
 
7
 
8
 from tracim_backend.lib.utils.utils import DATETIME_FORMAT
8
 from tracim_backend.lib.utils.utils import DATETIME_FORMAT
9
 from tracim_backend.models.auth import Profile
9
 from tracim_backend.models.auth import Profile
10
+
11
+from tracim_backend.app_models.contents import GlobalStatus
12
+from tracim_backend.app_models.contents import CONTENT_STATUS
13
+from tracim_backend.app_models.contents import CONTENT_TYPES
14
+from tracim_backend.app_models.contents import open_status
10
 from tracim_backend.models.auth import Group
15
 from tracim_backend.models.auth import Group
11
-from tracim_backend.models.contents import GlobalStatus
12
-from tracim_backend.models.contents import CONTENT_STATUS
13
-from tracim_backend.models.contents import CONTENT_TYPES
14
-from tracim_backend.models.contents import open_status
15
 from tracim_backend.models.context_models import ActiveContentFilter
16
 from tracim_backend.models.context_models import ActiveContentFilter
16
 from tracim_backend.models.context_models import FolderContentUpdate
17
 from tracim_backend.models.context_models import FolderContentUpdate
17
 from tracim_backend.models.context_models import AutocompleteQuery
18
 from tracim_backend.models.context_models import AutocompleteQuery
41
 from tracim_backend.models.context_models import LoginCredentials
42
 from tracim_backend.models.context_models import LoginCredentials
42
 from tracim_backend.models.data import UserRoleInWorkspace
43
 from tracim_backend.models.data import UserRoleInWorkspace
43
 from tracim_backend.models.data import ActionDescription
44
 from tracim_backend.models.data import ActionDescription
45
+from tracim_backend.app_models.validator import all_content_types_validator
44
 
46
 
45
 
47
 
46
 class UserDigestSchema(marshmallow.Schema):
48
 class UserDigestSchema(marshmallow.Schema):
390
     content_type = marshmallow.fields.String(
392
     content_type = marshmallow.fields.String(
391
         example=CONTENT_TYPES.Any_SLUG,
393
         example=CONTENT_TYPES.Any_SLUG,
392
         default=CONTENT_TYPES.Any_SLUG,
394
         default=CONTENT_TYPES.Any_SLUG,
393
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug())
395
+        validate=all_content_types_validator
394
     )
396
     )
395
 
397
 
396
     @post_load
398
     @post_load
641
 class ContentTypeSchema(marshmallow.Schema):
643
 class ContentTypeSchema(marshmallow.Schema):
642
     slug = marshmallow.fields.String(
644
     slug = marshmallow.fields.String(
643
         example='pagehtml',
645
         example='pagehtml',
644
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
646
+        validate=all_content_types_validator,
645
     )
647
     )
646
     fa_icon = marshmallow.fields.String(
648
     fa_icon = marshmallow.fields.String(
647
         example='fa-file-text-o',
649
         example='fa-file-text-o',
695
     )
697
     )
696
     content_type = marshmallow.fields.String(
698
     content_type = marshmallow.fields.String(
697
         example='html-document',
699
         example='html-document',
698
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
700
+        validate=all_content_types_validator,
699
     )
701
     )
700
     parent_id = marshmallow.fields.Integer(
702
     parent_id = marshmallow.fields.Integer(
701
         example=35,
703
         example=35,
730
     label = marshmallow.fields.Str(example='Intervention Report 12')
732
     label = marshmallow.fields.Str(example='Intervention Report 12')
731
     content_type = marshmallow.fields.Str(
733
     content_type = marshmallow.fields.Str(
732
         example='html-document',
734
         example='html-document',
733
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
735
+        validate=all_content_types_validator,
734
     )
736
     )
735
     sub_content_types = marshmallow.fields.List(
737
     sub_content_types = marshmallow.fields.List(
736
         marshmallow.fields.String(
738
         marshmallow.fields.String(
737
             example='html-content',
739
             example='html-content',
738
-            validate=OneOf(CONTENT_TYPES.extended_endpoint_allowed_types_slug())
740
+            validate=all_content_types_validator
739
         ),
741
         ),
740
         description='list of content types allowed as sub contents. '
742
         description='list of content types allowed as sub contents. '
741
                     'This field is required for folder contents, '
743
                     'This field is required for folder contents, '
885
     sub_content_types = marshmallow.fields.List(
887
     sub_content_types = marshmallow.fields.List(
886
         marshmallow.fields.String(
888
         marshmallow.fields.String(
887
             example='html-document',
889
             example='html-document',
888
-            validate=OneOf(CONTENT_TYPES.extended_endpoint_allowed_types_slug())
890
+            validate=all_content_types_validator,
889
         ),
891
         ),
890
         description='list of content types allowed as sub contents. '
892
         description='list of content types allowed as sub contents. '
891
                     'This field is required for folder contents, '
893
                     'This field is required for folder contents, '

+ 1 - 1
backend/tracim_backend/views/core_api/session_controller.py Zobrazit soubor

5
 except ImportError:
5
 except ImportError:
6
     from http import client as HTTPStatus
6
     from http import client as HTTPStatus
7
 
7
 
8
-from tracim_backend import TracimRequest
8
+from tracim_backend.lib.utils.request import TracimRequest
9
 from tracim_backend.extensions import hapic
9
 from tracim_backend.extensions import hapic
10
 from tracim_backend.lib.core.user import UserApi
10
 from tracim_backend.lib.core.user import UserApi
11
 from tracim_backend.views.controllers import Controller
11
 from tracim_backend.views.controllers import Controller

+ 9 - 4
backend/tracim_backend/views/core_api/system_controller.py Zobrazit soubor

2
 from pyramid.config import Configurator
2
 from pyramid.config import Configurator
3
 from tracim_backend.exceptions import NotAuthenticated
3
 from tracim_backend.exceptions import NotAuthenticated
4
 from tracim_backend.exceptions import InsufficientUserProfile
4
 from tracim_backend.exceptions import InsufficientUserProfile
5
+from tracim_backend.lib.core.application import ApplicationApi
5
 from tracim_backend.lib.utils.authorization import require_profile
6
 from tracim_backend.lib.utils.authorization import require_profile
6
 from tracim_backend.models import Group
7
 from tracim_backend.models import Group
7
-from tracim_backend.models.applications import applications
8
-from tracim_backend.models.contents import CONTENT_TYPES
8
+from tracim_backend.app_models.contents import CONTENT_TYPES
9
 
9
 
10
 try:  # Python 3.5+
10
 try:  # Python 3.5+
11
     from http import HTTPStatus
11
     from http import HTTPStatus
12
 except ImportError:
12
 except ImportError:
13
     from http import client as HTTPStatus
13
     from http import client as HTTPStatus
14
 
14
 
15
-from tracim_backend import TracimRequest
15
+from tracim_backend.lib.utils.request import TracimRequest
16
 from tracim_backend.extensions import hapic
16
 from tracim_backend.extensions import hapic
17
+from tracim_backend.extensions import app_list
17
 from tracim_backend.views.controllers import Controller
18
 from tracim_backend.views.controllers import Controller
18
 from tracim_backend.views.core_api.schemas import ApplicationSchema
19
 from tracim_backend.views.core_api.schemas import ApplicationSchema
19
 from tracim_backend.views.core_api.schemas import ContentTypeSchema
20
 from tracim_backend.views.core_api.schemas import ContentTypeSchema
30
         """
31
         """
31
         Get list of alls applications installed in this tracim instance.
32
         Get list of alls applications installed in this tracim instance.
32
         """
33
         """
33
-        return applications
34
+        app_config = request.registry.settings['CFG']
35
+        app_api = ApplicationApi(
36
+            app_list=app_list,
37
+        )
38
+        return app_api.get_all()
34
 
39
 
35
     @hapic.with_api_doc(tags=[SWAGGER_TAG_SYSTEM_ENDPOINTS])
40
     @hapic.with_api_doc(tags=[SWAGGER_TAG_SYSTEM_ENDPOINTS])
36
     @require_profile(Group.TIM_USER)
41
     @require_profile(Group.TIM_USER)

+ 2 - 2
backend/tracim_backend/views/core_api/user_controller.py Zobrazit soubor

7
     from http import client as HTTPStatus
7
     from http import client as HTTPStatus
8
 
8
 
9
 from tracim_backend import hapic
9
 from tracim_backend import hapic
10
-from tracim_backend import TracimRequest
10
+from tracim_backend.lib.utils.request import TracimRequest
11
 from tracim_backend.models import Group
11
 from tracim_backend.models import Group
12
 from tracim_backend.lib.core.group import GroupApi
12
 from tracim_backend.lib.core.group import GroupApi
13
 from tracim_backend.lib.core.user import UserApi
13
 from tracim_backend.lib.core.user import UserApi
36
 from tracim_backend.views.core_api.schemas import ContentDigestSchema
36
 from tracim_backend.views.core_api.schemas import ContentDigestSchema
37
 from tracim_backend.views.core_api.schemas import ActiveContentFilterQuerySchema
37
 from tracim_backend.views.core_api.schemas import ActiveContentFilterQuerySchema
38
 from tracim_backend.views.core_api.schemas import WorkspaceDigestSchema
38
 from tracim_backend.views.core_api.schemas import WorkspaceDigestSchema
39
-from tracim_backend.models.contents import CONTENT_TYPES
39
+from tracim_backend.app_models.contents import CONTENT_TYPES
40
 
40
 
41
 SWAGGER_TAG__USER_ENDPOINTS = 'Users'
41
 SWAGGER_TAG__USER_ENDPOINTS = 'Users'
42
 
42
 

+ 2 - 2
backend/tracim_backend/views/core_api/workspace_controller.py Zobrazit soubor

12
     from http import client as HTTPStatus
12
     from http import client as HTTPStatus
13
 
13
 
14
 from tracim_backend import hapic
14
 from tracim_backend import hapic
15
+from tracim_backend.lib.utils.request import TracimRequest
15
 from tracim_backend import BASE_API_V2
16
 from tracim_backend import BASE_API_V2
16
-from tracim_backend import TracimRequest
17
 from tracim_backend.lib.core.workspace import WorkspaceApi
17
 from tracim_backend.lib.core.workspace import WorkspaceApi
18
 from tracim_backend.lib.core.content import ContentApi
18
 from tracim_backend.lib.core.content import ContentApi
19
 from tracim_backend.lib.core.userworkspace import RoleApi
19
 from tracim_backend.lib.core.userworkspace import RoleApi
52
 from tracim_backend.views.core_api.schemas import WorkspaceSchema
52
 from tracim_backend.views.core_api.schemas import WorkspaceSchema
53
 from tracim_backend.views.core_api.schemas import WorkspaceIdPathSchema
53
 from tracim_backend.views.core_api.schemas import WorkspaceIdPathSchema
54
 from tracim_backend.views.core_api.schemas import WorkspaceMemberSchema
54
 from tracim_backend.views.core_api.schemas import WorkspaceMemberSchema
55
-from tracim_backend.models.contents import CONTENT_TYPES
55
+from tracim_backend.app_models.contents import CONTENT_TYPES
56
 from tracim_backend.models.revision_protection import new_revision
56
 from tracim_backend.models.revision_protection import new_revision
57
 
57
 
58
 SWAGGER_TAG_WORKSPACE_ENDPOINTS = 'Workspaces'
58
 SWAGGER_TAG_WORKSPACE_ENDPOINTS = 'Workspaces'

+ 9 - 3
backend/tracim_backend/views/frontend.py Zobrazit soubor

2
 
2
 
3
 from pyramid.renderers import render_to_response
3
 from pyramid.renderers import render_to_response
4
 from pyramid.config import Configurator
4
 from pyramid.config import Configurator
5
+from tracim_backend.extensions import app_list
5
 from tracim_backend.exceptions import PageNotFound
6
 from tracim_backend.exceptions import PageNotFound
6
-from tracim_backend.models.applications import applications
7
+from tracim_backend.lib.core.application import ApplicationApi
8
+from tracim_backend.lib.utils.utils import Color
7
 from tracim_backend.views import BASE_API_V2
9
 from tracim_backend.views import BASE_API_V2
8
 from tracim_backend.lib.utils.request import TracimRequest
10
 from tracim_backend.lib.utils.request import TracimRequest
9
 from tracim_backend.views.controllers import Controller
11
 from tracim_backend.views.controllers import Controller
10
-import spectra
11
 
12
 
12
 INDEX_PAGE_NAME = 'index.mak'
13
 INDEX_PAGE_NAME = 'index.mak'
13
 APP_FRONTEND_PATH = 'app/{minislug}.app.js'
14
 APP_FRONTEND_PATH = 'app/{minislug}.app.js'
34
         app_config = request.registry.settings['CFG']
35
         app_config = request.registry.settings['CFG']
35
         # TODO - G.M - 2018-08-07 - Refactor autogen valid app list for frontend
36
         # TODO - G.M - 2018-08-07 - Refactor autogen valid app list for frontend
36
         frontend_apps = []
37
         frontend_apps = []
38
+        app_api = ApplicationApi(
39
+            app_list=app_list,
40
+        )
41
+        applications = app_api.get_all()
37
         for app in applications:
42
         for app in applications:
38
             app_frontend_path = APP_FRONTEND_PATH.replace('{minislug}',
43
             app_frontend_path = APP_FRONTEND_PATH.replace('{minislug}',
39
                                                           app.minislug)  # nopep8
44
                                                           app.minislug)  # nopep8
41
                                     app_frontend_path)  # nopep8
46
                                     app_frontend_path)  # nopep8
42
             if os.path.exists(app_path):
47
             if os.path.exists(app_path):
43
                 frontend_apps.append(app)
48
                 frontend_apps.append(app)
49
+
44
         return render_to_response(
50
         return render_to_response(
45
             self._get_index_file_path(),
51
             self._get_index_file_path(),
46
             {
52
             {
47
                 'colors': {
53
                 'colors': {
48
-                    'primary': spectra.html('#7d4e24'),
54
+                    'primary': Color(app_config.APPS_COLORS['primary']),
49
                 },
55
                 },
50
                 'applications': frontend_apps,
56
                 'applications': frontend_apps,
51
             }
57
             }

+ 10 - 0
backend/wsgidav-test.conf Zobrazit soubor

1
+host  = "0.0.0.0"
2
+port = 3030
3
+show_history = True
4
+show_deleted = True
5
+show_archived = True
6
+manager_locks = True
7
+root_path = ''
8
+acceptbasic = True
9
+acceptdigest = False
10
+defaultdigest = False

+ 5 - 0
backend_lib.sh Zobrazit soubor

37
        log "generate missing wsgidav.conf ..."
37
        log "generate missing wsgidav.conf ..."
38
        cp wsgidav.conf.sample wsgidav.conf
38
        cp wsgidav.conf.sample wsgidav.conf
39
     fi
39
     fi
40
+
41
+    if [ ! -f ../color.json ]; then
42
+       log "generate missing color.json ..."
43
+       cp ../color.json.sample ../color.json
44
+    fi
40
 }
45
 }
41
 
46
 
42
 function setup_db {
47
 function setup_db {

+ 3 - 3
color.json.sample Zobrazit soubor

1
 {
1
 {
2
   "primary": "#7d4e24",
2
   "primary": "#7d4e24",
3
-  "html-document": "#3f52e3",
4
-  "thread": "#ad4cf9",
5
-  "file": "#ff9900"
3
+  "contents/html-document": "#3f52e3",
4
+  "contents/thread": "#ad4cf9",
5
+  "contents/file": "#ff9900"
6
 }
6
 }

+ 18 - 18
frontend/dist/index.mak Zobrazit soubor

21
         param = 'color'
21
         param = 'color'
22
         color_change_value = 15
22
         color_change_value = 15
23
       %>
23
       %>
24
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
25
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
26
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
24
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
25
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
26
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
27
       <% html_class = '.primaryColorFont{state}Hover:hover' %>
27
       <% html_class = '.primaryColorFont{state}Hover:hover' %>
28
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
29
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
30
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
28
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
29
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
30
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
31
 
31
 
32
       <%
32
       <%
33
         html_class = '.primaryColorBg{state}'
33
         html_class = '.primaryColorBg{state}'
34
         param = 'background-color'
34
         param = 'background-color'
35
       %>
35
       %>
36
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
37
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
38
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
36
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
37
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
38
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
39
       <% html_class = '.primaryColorBg{state}Hover:hover'%>
39
       <% html_class = '.primaryColorBg{state}Hover:hover'%>
40
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
41
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
42
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
40
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
41
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
42
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
43
 
43
 
44
       <%
44
       <%
45
         param = 'border-color'
45
         param = 'border-color'
46
         html_class = '.primaryColorBorder{state}'
46
         html_class = '.primaryColorBorder{state}'
47
       %>
47
       %>
48
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
49
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
50
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
48
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
49
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
50
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
51
       <% html_class = '.primaryColorBorder{state}Hover:hover' %>
51
       <% html_class = '.primaryColorBorder{state}Hover:hover' %>
52
-      ${html_class.replace('{state}', '')} { ${param}: ${primary.hexcode}; }
53
-      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken(color_change_value).hexcode}; }
54
-      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.brighten(color_change_value).hexcode}; }
52
+      ${html_class.replace('{state}', '')} { ${param}: ${primary.normal}; }
53
+      ${html_class.replace('{state}', 'Darken')} { ${param}: ${primary.darken}; }
54
+      ${html_class.replace('{state}', 'Lighten')} { ${param}: ${primary.lighten}; }
55
     </style>
55
     </style>
56
   </head>
56
   </head>
57
 
57