Browse Source

Big refactoring of App + Experimental support for color.json

Guénaël Muller 5 years ago
parent
commit
abfcc27c83
46 changed files with 560 additions and 417 deletions
  1. 1 0
      .gitignore
  2. 4 0
      backend/README.md
  3. 7 0
      backend/development.ini.sample
  4. 71 0
      backend/tracim_backend/app_models/applications.py
  5. 37 73
      backend/tracim_backend/app_models/contents.py
  6. 11 0
      backend/tracim_backend/app_models/validator.py
  7. 33 0
      backend/tracim_backend/app_models/workspace_menu_entries.py
  8. 148 4
      backend/tracim_backend/config.py
  9. 4 0
      backend/tracim_backend/exceptions.py
  10. 11 0
      backend/tracim_backend/extensions.py
  11. 1 1
      backend/tracim_backend/fixtures/content.py
  12. 70 0
      backend/tracim_backend/lib/core/application.py
  13. 3 3
      backend/tracim_backend/lib/core/content.py
  14. 1 1
      backend/tracim_backend/lib/mail_notifier/notifier.py
  15. 1 1
      backend/tracim_backend/lib/utils/authentification.py
  16. 5 7
      backend/tracim_backend/lib/utils/authorization.py
  17. 1 1
      backend/tracim_backend/lib/utils/request.py
  18. 4 5
      backend/tracim_backend/lib/utils/utils.py
  19. 1 1
      backend/tracim_backend/lib/webdav/dav_provider.py
  20. 1 1
      backend/tracim_backend/lib/webdav/design.py
  21. 1 1
      backend/tracim_backend/lib/webdav/resources.py
  22. 1 1
      backend/tracim_backend/lib/webdav/utils.py
  23. 1 1
      backend/tracim_backend/models/__init__.py
  24. 0 117
      backend/tracim_backend/models/applications.py
  25. 8 4
      backend/tracim_backend/models/context_models.py
  26. 3 3
      backend/tracim_backend/models/data.py
  27. 0 71
      backend/tracim_backend/models/workspace_menu_entries.py
  28. 1 1
      backend/tracim_backend/tests/__init__.py
  29. 1 1
      backend/tracim_backend/tests/functional/test_contents.py
  30. 1 1
      backend/tracim_backend/tests/functional/test_mail_notification.py
  31. 10 2
      backend/tracim_backend/tests/functional/test_system.py
  32. 26 39
      backend/tracim_backend/tests/functional/test_user.py
  33. 46 42
      backend/tracim_backend/tests/functional/test_workspaces.py
  34. 1 1
      backend/tracim_backend/tests/library/test_content_api.py
  35. 1 1
      backend/tracim_backend/tests/models/test_content.py
  36. 1 1
      backend/tracim_backend/tests/models/test_content_revision.py
  37. 2 2
      backend/tracim_backend/views/contents_api/comment_controller.py
  38. 3 3
      backend/tracim_backend/views/contents_api/file_controller.py
  39. 3 3
      backend/tracim_backend/views/contents_api/html_document_controller.py
  40. 3 3
      backend/tracim_backend/views/contents_api/threads_controller.py
  41. 10 9
      backend/tracim_backend/views/core_api/schemas.py
  42. 1 1
      backend/tracim_backend/views/core_api/session_controller.py
  43. 9 5
      backend/tracim_backend/views/core_api/system_controller.py
  44. 2 2
      backend/tracim_backend/views/core_api/user_controller.py
  45. 2 2
      backend/tracim_backend/views/core_api/workspace_controller.py
  46. 8 2
      backend/tracim_backend/views/frontend.py

+ 1 - 0
.gitignore View File

@@ -6,3 +6,4 @@ frontend_app_html-document/dist/html-document.app.js
6 6
 frontend_lib/dist/tracim_frontend_lib.js
7 7
 npm-debug.log
8 8
 package-lock.json
9
+color.json

+ 4 - 0
backend/README.md View File

@@ -81,6 +81,10 @@ create wsgidav configuration file for webdav:
81 81
 
82 82
     cp wsgidav.conf.sample wsgidav.conf
83 83
 
84
+if not did before, you need to create a color.json file at root of tracim_v2 :
85
+   
86
+    cp ../color.json.sample ../color.json
87
+
84 88
 ## Run Tracim_backend ##
85 89
 
86 90
 ### With Uwsgi ###

+ 7 - 0
backend/development.ini.sample View File

@@ -193,6 +193,13 @@ frontend.serve = True
193 193
 # organisation.
194 194
 # frontend.dist_folder_path = /home/user/tracim_v2/frontend/dist
195 195
 
196
+### Color
197
+# check for color.json file in tracim_v2, check by default in tracim_v2 parent
198
+# dir of backend.
199
+# you can set a specific file path here
200
+# color.config_file_path = /home/user/tracim_v2/color.json
201
+
202
+
196 203
 ###
197 204
 # wsgi server configuration
198 205
 ###

+ 71 - 0
backend/tracim_backend/app_models/applications.py View File

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

backend/tracim_backend/models/contents.py → backend/tracim_backend/app_models/contents.py View File

@@ -2,17 +2,13 @@
2 2
 import typing
3 3
 from enum import Enum
4 4
 
5
+from tracim_backend.extensions import APP_LIST
5 6
 from tracim_backend.exceptions import ContentTypeNotExist
6 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 10
 # Content Status
11
+from tracim_backend.lib.core.application import ApplicationApi
16 12
 
17 13
 
18 14
 class GlobalStatus(Enum):
@@ -132,59 +128,17 @@ class ContentType(object):
132 128
         self.slug_alias = slug_alias
133 129
 
134 130
 
135
-thread_type = ContentType(
136
-    slug='thread',
137
-    fa_icon=thread.fa_icon,
138
-    hexcolor=thread.hexcolor,
139
-    label='Thread',
140
-    creation_label='Discuss about a topic',
141
-    available_statuses=CONTENT_STATUS.get_all(),
142
-)
143
-
144
-file_type = ContentType(
145
-    slug='file',
146
-    fa_icon=_file.fa_icon,
147
-    hexcolor=_file.hexcolor,
148
-    label='File',
149
-    creation_label='Upload a file',
150
-    available_statuses=CONTENT_STATUS.get_all(),
151
-)
152
-
153
-markdownpluspage_type = ContentType(
154
-    slug='markdownpage',
155
-    fa_icon=markdownpluspage.fa_icon,
156
-    hexcolor=markdownpluspage.hexcolor,
157
-    label='Rich Markdown File',
158
-    creation_label='Create a Markdown document',
159
-    available_statuses=CONTENT_STATUS.get_all(),
160
-)
161
-
162
-html_documents_type = ContentType(
163
-    slug='html-document',
164
-    fa_icon=html_documents.fa_icon,
165
-    hexcolor=html_documents.hexcolor,
166
-    label='Text Document',
167
-    creation_label='Write a document',
168
-    available_statuses=CONTENT_STATUS.get_all(),
169
-    slug_alias=['page']
170
-)
171
-
172
-# TODO - G.M - 31-05-2018 - Set Better folder params
173
-folder_type = ContentType(
174
-    slug='folder',
175
-    fa_icon=folder.fa_icon,
176
-    hexcolor=folder.hexcolor,
177
-    label='Folder',
178
-    creation_label='Create a folder',
179
-    available_statuses=CONTENT_STATUS.get_all(),
180
-)
181
-
131
+thread_type = 'thread'
132
+file_type = 'file'
133
+markdownpluspage_type = 'markdownpage'
134
+html_documents_type = 'html-document'
135
+folder_type = 'folder'
182 136
 
183 137
 # TODO - G.M - 31-05-2018 - Set Better Event params
184 138
 event_type = ContentType(
185 139
     slug='event',
186
-    fa_icon=thread.fa_icon,
187
-    hexcolor=thread.hexcolor,
140
+    fa_icon='',
141
+    hexcolor='',
188 142
     label='Event',
189 143
     creation_label='Event',
190 144
     available_statuses=CONTENT_STATUS.get_all(),
@@ -193,8 +147,8 @@ event_type = ContentType(
193 147
 # TODO - G.M - 31-05-2018 - Set Better Event params
194 148
 comment_type = ContentType(
195 149
     slug='comment',
196
-    fa_icon=thread.fa_icon,
197
-    hexcolor=thread.hexcolor,
150
+    fa_icon='',
151
+    hexcolor='',
198 152
     label='Comment',
199 153
     creation_label='Comment',
200 154
     available_statuses=CONTENT_STATUS.get_all(),
@@ -206,19 +160,37 @@ class ContentTypeList(object):
206 160
     ContentType List
207 161
     """
208 162
     Any_SLUG = 'any'
209
-    Folder = folder_type
210 163
     Comment = comment_type
211 164
     Event = event_type
212
-    File = file_type
213
-    Page = html_documents_type
214
-    Thread = thread_type
215 165
 
216
-    def __init__(self, extend_content_status: typing.List[ContentType]):
217
-        self._content_types = [self.Folder]
218
-        self._content_types.extend(extend_content_status)
166
+    @property
167
+    def Folder(self):
168
+        return self.get_one_by_slug('folder')
169
+
170
+    @property
171
+    def File(self):
172
+        return self.get_one_by_slug('file')
173
+
174
+    @property
175
+    def Page(self):
176
+        return self.get_one_by_slug('html-document')
177
+
178
+    @property
179
+    def Thread(self):
180
+        return self.get_one_by_slug('thread')
181
+
182
+    def __init__(self, app_list: typing.List['Application']):
183
+        self.app_list = app_list
219 184
         self._special_contents_types = [self.Comment]
220 185
         self._extra_slugs = [self.Any_SLUG]
221 186
 
187
+    @property
188
+    def _content_types(self):
189
+        app_api = ApplicationApi(self.app_list)
190
+        content_types = app_api.get_content_types()
191
+        content_types.extend(self._special_contents_types)
192
+        return content_types
193
+
222 194
     def get_one_by_slug(self, slug: str) -> ContentType:
223 195
         """
224 196
         Get ContentType object according to slug
@@ -258,12 +230,4 @@ class ContentTypeList(object):
258 230
         return allowed_types_slug
259 231
 
260 232
 
261
-CONTENT_TYPES = ContentTypeList(
262
-    [
263
-        thread_type,
264
-        file_type,
265
-        # TODO - G.M - 2018-08-02 - Restore markdown page content
266
-        #    markdownpluspage_type,
267
-        html_documents_type,
268
-    ]
269
-)
233
+CONTENT_TYPES = ContentTypeList(APP_LIST)

+ 11 - 0
backend/tracim_backend/app_models/validator.py View File

@@ -0,0 +1,11 @@
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 View File

@@ -0,0 +1,33 @@
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
+)

+ 148 - 4
backend/tracim_backend/config.py View File

@@ -1,15 +1,19 @@
1 1
 # -*- coding: utf-8 -*-
2
+import json
2 3
 from urllib.parse import urlparse
3 4
 
4 5
 import os
5 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 9
 from tracim_backend.lib.utils.logger import logger
7 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 14
 from tracim_backend.models.data import ActionDescription
10 15
 
11 16
 
12
-
13 17
 class CFG(object):
14 18
     """Object used for easy access to config file parameters."""
15 19
 
@@ -41,7 +45,36 @@ class CFG(object):
41 45
         ###
42 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 78
         mandatory_msg = \
46 79
             'ERROR: {} configuration is mandatory. Set it before continuing.'
47 80
         self.DEPOT_STORAGE_DIR = settings.get(
@@ -450,8 +483,6 @@ class CFG(object):
450 483
         # INFO - G.M - 2018-08-06 - we pretend that frontend_dist_folder
451 484
         # is probably in frontend subfolder
452 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 486
         frontend_dist_folder = os.path.join(tracim_v2_folder, 'frontend', 'dist')  # nopep8
456 487
 
457 488
         self.FRONTEND_DIST_FOLDER_PATH = settings.get(
@@ -467,6 +498,10 @@ class CFG(object):
467 498
             )
468 499
 
469 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 505
         depot_storage_name = self.DEPOT_STORAGE_NAME
471 506
         depot_storage_path = self.DEPOT_STORAGE_DIR
472 507
         depot_storage_settings = {'depot.storage_path': depot_storage_path}
@@ -475,6 +510,115 @@ class CFG(object):
475 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
+        )
555
+
556
+        _file = Application(
557
+            label='Files',
558
+            slug='contents/file',
559
+            fa_icon='paperclip',
560
+            is_active=True,
561
+            config={},
562
+            main_route='/#/workspaces/{workspace_id}/contents?type=file',
563
+            app_config=self,
564
+        )
565
+        _file.add_content_type(
566
+            slug='file',
567
+            label='File',
568
+            creation_label='Upload a file',
569
+            available_statuses=CONTENT_STATUS.get_all(),
570
+        )
571
+
572
+        markdownpluspage = Application(
573
+            label='Markdown Plus Documents',
574
+            # TODO - G.M - 24-05-2018 - Check label
575
+            slug='content/markdownpluspage',
576
+            fa_icon='file-code-o',
577
+            is_active=False,
578
+            config={},
579
+            main_route='/#/workspaces/{workspace_id}/contents?type=markdownpluspage',
580
+            # nopep8
581
+            app_config=self,
582
+        )
583
+        markdownpluspage.add_content_type(
584
+            slug='markdownpage',
585
+            label='Rich Markdown File',
586
+            creation_label='Create a Markdown document',
587
+            available_statuses=CONTENT_STATUS.get_all(),
588
+        )
589
+
590
+        html_documents = Application(
591
+            label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
592
+            slug='contents/html-document',
593
+            fa_icon='file-text-o',
594
+            is_active=True,
595
+            config={},
596
+            main_route='/#/workspaces/{workspace_id}/contents?type=html-document',
597
+            app_config=self
598
+        )
599
+        html_documents.add_content_type(
600
+            slug='html-document',
601
+            label='Text Document',
602
+            creation_label='Write a document',
603
+            available_statuses=CONTENT_STATUS.get_all(),
604
+            slug_alias=['page']
605
+        )
606
+
607
+        # TODO - G.M - 2018-08-08 - [GlobalVar] Refactor Global var
608
+        # of tracim_backend, Be careful APP_LIST is a global_var
609
+        APP_LIST.clear()
610
+        APP_LIST.extend([
611
+            html_documents,
612
+            markdownpluspage,
613
+            _file,
614
+            thread,
615
+            folder,
616
+            calendar,
617
+        ])
618
+        # TODO - G.M - 2018-08-08 - We need to update validators each time
619
+        # APP_LIST is updated.
620
+        update_validators()
621
+
478 622
     class CST(object):
479 623
         ASYNC = 'ASYNC'
480 624
         SYNC = 'SYNC'

+ 4 - 0
backend/tracim_backend/exceptions.py View File

@@ -211,3 +211,7 @@ class TooShortAutocompleteString(TracimException):
211 211
 
212 212
 class PageNotFound(TracimException):
213 213
     pass
214
+
215
+
216
+class AppDoesNotExist(TracimException):
217
+    pass

+ 11 - 0
backend/tracim_backend/extensions.py View File

@@ -1,3 +1,14 @@
1 1
 from hapic import Hapic
2 2
 
3 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 View File

@@ -8,7 +8,7 @@ from tracim_backend.fixtures.users_and_groups import Test
8 8
 from tracim_backend.lib.core.content import ContentApi
9 9
 from tracim_backend.lib.core.userworkspace import RoleApi
10 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 12
 from tracim_backend.models.data import UserRoleInWorkspace
13 13
 from tracim_backend.models.revision_protection import new_revision
14 14
 

+ 70 - 0
backend/tracim_backend/lib/core/application.py View File

@@ -0,0 +1,70 @@
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

+ 3 - 3
backend/tracim_backend/lib/core/content.py View File

@@ -34,9 +34,9 @@ from tracim_backend.exceptions import EmptyLabelNotAllowed
34 34
 from tracim_backend.exceptions import ContentNotFound
35 35
 from tracim_backend.exceptions import WorkspacesDoNotMatch
36 36
 from tracim_backend.lib.utils.utils import current_date_for_filename
37
-from tracim_backend.models.contents import CONTENT_STATUS
38
-from tracim_backend.models.contents import ContentType
39
-from tracim_backend.models.contents import CONTENT_TYPES
37
+from tracim_backend.app_models.contents import CONTENT_STATUS
38
+from tracim_backend.app_models.contents import ContentType
39
+from tracim_backend.app_models.contents import CONTENT_TYPES
40 40
 from tracim_backend.models.revision_protection import new_revision
41 41
 from tracim_backend.models.auth import User
42 42
 from tracim_backend.models.data import ActionDescription

+ 1 - 1
backend/tracim_backend/lib/mail_notifier/notifier.py View File

@@ -20,7 +20,7 @@ from tracim_backend.lib.utils.logger import logger
20 20
 from tracim_backend.lib.utils.utils import get_login_frontend_url
21 21
 from tracim_backend.lib.utils.utils import get_email_logo_frontend_url
22 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 24
 from tracim_backend.models.context_models import ContentInContext
25 25
 from tracim_backend.models.context_models import WorkspaceInContext
26 26
 from tracim_backend.models.data import ActionDescription

+ 1 - 1
backend/tracim_backend/lib/utils/authentification.py View File

@@ -3,7 +3,7 @@ import typing
3 3
 from pyramid.request import Request
4 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 7
 from tracim_backend.exceptions import UserDoesNotExist
8 8
 from tracim_backend.lib.core.user import UserApi
9 9
 from tracim_backend.models import User

+ 5 - 7
backend/tracim_backend/lib/utils/authorization.py View File

@@ -5,15 +5,14 @@ import functools
5 5
 from pyramid.interfaces import IAuthorizationPolicy
6 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 11
 try:
12 12
     from json.decoder import JSONDecodeError
13 13
 except ImportError:  # python3.4
14 14
     JSONDecodeError = ValueError
15 15
 
16
-from tracim_backend.models.contents import ContentType
17 16
 from tracim_backend.exceptions import InsufficientUserRoleInWorkspace
18 17
 from tracim_backend.exceptions import ContentTypeNotAllowed
19 18
 from tracim_backend.exceptions import InsufficientUserProfile
@@ -133,19 +132,18 @@ def require_candidate_workspace_role(minimal_required_role: int) -> typing.Calla
133 132
     return decorator
134 133
 
135 134
 
136
-def require_content_types(content_types: typing.List['ContentType']) -> typing.Callable:  # nopep8
135
+def require_content_types(content_types_slug: typing.List[str]) -> typing.Callable:  # nopep8
137 136
     """
138 137
     Restricts access to specific file type or raise an exception.
139 138
     Check role for candidate_workspace.
140
-    :param content_types: list of ContentType object
139
+    :param content_types_slug: list of slug of content_types
141 140
     :return: decorator
142 141
     """
143 142
     def decorator(func: typing.Callable) -> typing.Callable:
144 143
         @functools.wraps(func)
145 144
         def wrapper(self, context, request: 'TracimRequest') -> typing.Callable:
146 145
             content = request.current_content
147
-            current_content_type_slug = CONTENT_TYPES.get_one_by_slug(content.type).slug
148
-            content_types_slug = [content_type.slug for content_type in content_types]  # nopep8
146
+            current_content_type_slug = CONTENT_TYPES.get_one_by_slug(content.type).slug  # nopep8
149 147
             if current_content_type_slug in content_types_slug:
150 148
                 return func(self, context, request)
151 149
             raise ContentTypeNotAllowed()

+ 1 - 1
backend/tracim_backend/lib/utils/request.py View File

@@ -15,7 +15,7 @@ from tracim_backend.exceptions import UserNotFoundInTracimRequest
15 15
 from tracim_backend.exceptions import UserDoesNotExist
16 16
 from tracim_backend.exceptions import WorkspaceNotFound
17 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 19
 from tracim_backend.lib.core.content import ContentApi
20 20
 from tracim_backend.lib.core.user import UserApi
21 21
 from tracim_backend.lib.core.workspace import WorkspaceApi

+ 4 - 5
backend/tracim_backend/lib/utils/utils.py View File

@@ -7,7 +7,6 @@ from enum import Enum
7 7
 from redis import Redis
8 8
 from rq import Queue
9 9
 
10
-from tracim_backend.config import CFG
11 10
 
12 11
 DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
13 12
 DEFAULT_WEBDAV_CONFIG_FILE = "wsgidav.conf"
@@ -16,7 +15,7 @@ CONTENT_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}/contents/{content_type}
16 15
 WORKSPACE_FRONTEND_URL_SCHEMA = 'workspaces/{workspace_id}'  # nopep8
17 16
 
18 17
 
19
-def get_root_frontend_url(config: CFG) -> str:
18
+def get_root_frontend_url(config: 'CFG') -> str:
20 19
     """
21 20
     Return website base url with always '/' at the end
22 21
     """
@@ -28,19 +27,19 @@ def get_root_frontend_url(config: CFG) -> str:
28 27
     return base_url
29 28
 
30 29
 
31
-def get_login_frontend_url(config: CFG):
30
+def get_login_frontend_url(config: 'CFG'):
32 31
     """
33 32
     Return login page url
34 33
     """
35 34
     return get_root_frontend_url(config) + 'login'
36 35
 
37 36
 
38
-def get_email_logo_frontend_url(config: CFG):
37
+def get_email_logo_frontend_url(config: 'CFG'):
39 38
     # TODO - G.M - 11-06-2018 - [emailTemplateURL] correct value for email_logo_frontend_url  # nopep8
40 39
     return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4QUTDjMSlsws9AAAB89JREFUaN7tmWtwlFcZx3/PeXeXXLmKQJEGsFZApIUBnaqjUm4VgdYyCUib0cJoKLmHW5EWmlGoQkMICURgEPuhtiYDU7XcyVgKVugULZVCQAwUYyENYAmEXHb3PH7IFjYQNgnZHfnA+bKz+7573v//PPf/C/fWvdWhJWHfMbO4P479OpCAigeowWglPq3ARWfU9AJ7Cb/3MAXZn95dBLKKHsfIQmAUIq7rv6t6gU+BKCAGaEBkN9h88tLe7sgjTdjAJ5Y4OGYMIo80Aw8g4kakJyLxiDiIxABPoMwj5+XP3R0ESpP8WC1H1YuqBj4bUWwIB5gA0d/6/xFQFUpKHBJLHADyU9chTEc1BdEZqJ0O+ofb4xcPyuBIxoBQuHc4ov3w2zrwH0Nd0aBDccwgVPsjEg/4Uc4jegKfvkfMmQ9JSfECkFP0HGJeuu0TrJZhSacg9Xh4Caze2wsXC1B9GugO+BAqUIkC/QIinhYsYoEqYDt+fY2s8WXkFE5CnBIg+vaWtJuQukzy5te2l4Bz2ysTkxchshCRWERMU2BKT4RuiLT0vwagHsENPIyR7zAx2eGybws09AUZEQLHcNS5wMEdB8NjgaKyBNTuQuTLoWOAs6AHUd5DpRzxX0KMBe0M+gA4D4Hdw5mT72LJQORxkM6IfgxSC3wjyHpHEN8M8jKPtYeAq2VgvhHg9A4RvPUIKzCyBVe346SM9LZw1y5KShzOxfUhL60SmMfcNUXgisXYS/iNA/IzhNmBgH4I3E8Cxzpmgby9ffFoMSKTQxA4jZjRpI35qENZbF5Rb1SWgcwM7HsQr28KhZnVd55GPfqTkOCbaB+i2lR1uHa8nHYeda0EygJWGILHGXzndaBgz3CQ5Fb8/hSqr5E7uj4sBXBVSjlqN6FaixKHlS8BxCYtHhs/bUly9JT597U9C30/eRYiU4Nc5Q1gH+AG/gvsxJBH2vg3w9pDPTjqFDGxX0FkKOih2PtHOcbIBiPMMi5XT9eDo9/xlu+rDW2BpX+MAQnOCudRWcWFA3OwncYhrke5VpuK1SrW7+sTVgKv5NYjsr2p6TMY1QEGvhi4mmw89unWXaiX6QQEN1YHuHjpELm5lsxvV2MbhxAdWwCSiNfnCXsb7mc/Ih8hXED8J1T1k6awEAG+R+LCLqEJOL2vInwQOP46VHaSm9QYiI1nMU4xwv2oa3OHs0+LiaHuHKr/wOo/r1yuOQwcDEqVw2KdqITQBFJGelFWojITPz8kY+wmAAp3pWLkJVT7oGwkY3R5REar/Ln1qO7AyIfsLGxQ1eB60E3UDmi9kKWPOwmcvP69cM8kROYCXVB5FW18I4LToeLSbTGnKh2T9MIChLHBOI2lT9srMUDB9s7AM8CApj7H/yaZExsiOd9GnbngcjzOciPyVPOuW0RFB7ZvHnDck4FJgbOpwPoPRHpAdxs782bwQSwei3ty0aC2EVh61ANMutEy63Gi/l0VUfSJC7sIjAnhYYON4x7eNgI9KgeifDPIOyuuDygRWnGuKDcQF6roWrGxbSNgzDAgqBuV6ki7z9WT5y4DR0LdoqoVbSOgZhAi7hv4bXzEFarDG7yqbPmsgN2aovhdLdf+2jqBorIE4JGbIugZCvcsijQHr5ojN1tbVaustUWNNP6S0vy60AR+ut4Ndj7CYzdlgL7AixTtmRnRLOToVNAhQeDfR+yPr+iJrIbf/+pM62l0WP8RKNNCSCCTySuJjgT42MTnv4rqjEDvg6J+VH5T8/qynZSW+ts40EgCQtcQDcsDEN2d9IKe4U2hiR5jmG1ERt4QKrS4pkqK2zmRSQMaUsj6D5cuu3C5ppCY6IQLf2dn8CIjZk4Q+N961VnJvlxf+4Z6v/cojvsDYEQL4BXRHVTXfkysjqPfd3tA6YqOnXx293gnLgvV5xFBVa2iv/b6dEX91p+fbf9ImTnxX6gWAadbILARX+0rbEjxohwCFpBVlH1nyJea2KTFY+OduHUGeaFJoNN3gcwr1smu37qsze16y7pQ4a7pYFYj0iuAvho0jbTxJQBkrB6Ky70VGIDqamA9+WmnWtwrZ20/fN4uQA1rss52Slw8wIOZKg4/QIlTKBfY32DttobSZafDJS0Ka3YXYEx6UCXZid8/n6wJRwHIXrsEI7kB6+xHtQTDn8hLPQuipBb2oJOkgSQBPREuAlupq98cfa6mXsXnOFpfV5uQMBRxlMpP/kJpbmP4tNHC3SNBNiLycJAbleLlOXLGVTB33edRLUBkepAuegyRd1D7Pphh10Wr5mJuMT5fNo67L45NQSUlIBqsYlXqkqaiGy51es3eWQh5CDfmUeufTcaE9QBkFY7AyIuImXxT3bfI7doUvQayFbUDMSZYRHiLq64n2JByOXzvBzLGbkJ1GarnP4OPmBt60Or0v+E381Fdj+ILOhYT4p1ADOhTzcA3EdjeXvCtEwDIGNc0J6vNB/0FDXXbmk9uc05wMSYLq+nAgYArtWJ3keYW0eVUVheE9/3ArbYXkND+mbO2H8gk0AnAlGZAb3WlWpQ/I/o6q9JevWMxIyJdWWZ+V4xnOUaebQH4MVS2I/59eO3bFGbWdEiNiVhrmVncH+NfhMg0IA4RH1bfQnQlq9LKwiYnRbTB/9HmKLrWfg2j94HUoI1/Z3XOOe6te+vuWf8DkM0cb7DOQZgAAAAASUVORK5CYII='  # nopep8'
41 40
 
42 41
 
43
-def get_redis_connection(config: CFG) -> Redis:
42
+def get_redis_connection(config: 'CFG') -> Redis:
44 43
     """
45 44
     :param config: current app_config
46 45
     :return: redis connection

+ 1 - 1
backend/tracim_backend/lib/webdav/dav_provider.py View File

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

+ 1 - 1
backend/tracim_backend/lib/webdav/design.py View File

@@ -1,7 +1,7 @@
1 1
 #coding: utf8
2 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 5
 from tracim_backend.models.data import VirtualEvent
6 6
 from tracim_backend.models import data
7 7
 

+ 1 - 1
backend/tracim_backend/lib/webdav/resources.py View File

@@ -19,7 +19,7 @@ from tracim_backend.lib.webdav.utils import transform_to_display, HistoryType, \
19 19
     FakeFileStream
20 20
 from tracim_backend.lib.webdav.utils import transform_to_bdd
21 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 23
 from tracim_backend.models.data import User, ContentRevisionRO
24 24
 from tracim_backend.models.data import Workspace
25 25
 from tracim_backend.models.data import Content

+ 1 - 1
backend/tracim_backend/lib/webdav/utils.py View File

@@ -4,7 +4,7 @@ import transaction
4 4
 from os.path import normpath as base_normpath
5 5
 
6 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 8
 from wsgidav import util
9 9
 from wsgidav import compat
10 10
 

+ 1 - 1
backend/tracim_backend/models/__init__.py View File

@@ -5,7 +5,7 @@ from sqlalchemy.orm import sessionmaker
5 5
 from sqlalchemy.orm import configure_mappers
6 6
 import zope.sqlalchemy
7 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 9
 # import or define all models here to ensure they are attached to the
10 10
 # Base.metadata prior to any initialization routines
11 11
 from tracim_backend.models.auth import User, Group, Permission

+ 0 - 117
backend/tracim_backend/models/applications.py View File

@@ -1,117 +0,0 @@
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 View File

@@ -7,6 +7,8 @@ from slugify import slugify
7 7
 from sqlalchemy.orm import Session
8 8
 from tracim_backend.config import CFG
9 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 12
 from tracim_backend.lib.utils.utils import get_root_frontend_url
11 13
 from tracim_backend.lib.utils.utils import CONTENT_FRONTEND_URL_SCHEMA
12 14
 from tracim_backend.lib.utils.utils import WORKSPACE_FRONTEND_URL_SCHEMA
@@ -17,9 +19,8 @@ from tracim_backend.models.data import ContentRevisionRO
17 19
 from tracim_backend.models.data import Workspace
18 20
 from tracim_backend.models.data import UserRoleInWorkspace
19 21
 from tracim_backend.models.roles import WorkspaceRoles
20
-from tracim_backend.models.workspace_menu_entries import default_workspace_menu_entry  # nopep8
21
-from tracim_backend.models.workspace_menu_entries import WorkspaceMenuEntry
22
-from tracim_backend.models.contents import CONTENT_TYPES
22
+from tracim_backend.app_models.workspace_menu_entries import WorkspaceMenuEntry
23
+from tracim_backend.app_models.contents import CONTENT_TYPES
23 24
 
24 25
 
25 26
 class PreviewAllowedDim(object):
@@ -463,7 +464,10 @@ class WorkspaceInContext(object):
463 464
         # order to not use hardcoded list
464 465
         # list should be able to change (depending on activated/disabled
465 466
         # apps)
466
-        return default_workspace_menu_entry(self.workspace)
467
+        app_api = ApplicationApi(
468
+            APP_LIST
469
+        )
470
+        return app_api.get_default_workspace_menu_entry(self.workspace)
467 471
 
468 472
     @property
469 473
     def frontend_url(self):

+ 3 - 3
backend/tracim_backend/models/data.py View File

@@ -291,9 +291,9 @@ class ActionDescription(object):
291 291
                 ]
292 292
 
293 293
 
294
-from tracim_backend.models.contents import CONTENT_STATUS
295
-from tracim_backend.models.contents import ContentStatus
296
-from tracim_backend.models.contents import CONTENT_TYPES
294
+from tracim_backend.app_models.contents import CONTENT_STATUS
295
+from tracim_backend.app_models.contents import ContentStatus
296
+from tracim_backend.app_models.contents import CONTENT_TYPES
297 297
 # TODO - G.M - 30-05-2018 - Drop this old code when whe are sure nothing
298 298
 # is lost .
299 299
 

+ 0 - 71
backend/tracim_backend/models/workspace_menu_entries.py View File

@@ -1,71 +0,0 @@
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 View File

@@ -14,7 +14,7 @@ from tracim_backend.models import get_engine
14 14
 from tracim_backend.models import DeclarativeBase
15 15
 from tracim_backend.models import get_session_factory
16 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 18
 from tracim_backend.models.data import Workspace
19 19
 from tracim_backend.models.data import ContentRevisionRO
20 20
 from tracim_backend.models.data import Content

+ 1 - 1
backend/tracim_backend/tests/functional/test_contents.py View File

@@ -5,7 +5,7 @@ from tracim_backend import models
5 5
 from tracim_backend.lib.core.content import ContentApi
6 6
 from tracim_backend.lib.core.workspace import WorkspaceApi
7 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 9
 from tracim_backend.models.revision_protection import new_revision
10 10
 import io
11 11
 

+ 1 - 1
backend/tracim_backend/tests/functional/test_mail_notification.py View File

@@ -11,7 +11,7 @@ from tracim_backend.fixtures.users_and_groups import Base as BaseFixture
11 11
 from tracim_backend.fixtures.content import Content as ContentFixture
12 12
 from tracim_backend.lib.utils.utils import get_redis_connection
13 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 16
 from tracim_backend.lib.core.content import ContentApi
17 17
 from tracim_backend.lib.core.user import UserApi

+ 10 - 2
backend/tracim_backend/tests/functional/test_system.py View File

@@ -1,7 +1,10 @@
1 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 7
 from tracim_backend.tests import FunctionalTest
4
-from tracim_backend.models.applications import applications
5 8
 
6 9
 """
7 10
 Tests for /api/v2/system subpath endpoints.
@@ -26,6 +29,11 @@ class TestApplicationEndpoint(FunctionalTest):
26 29
         )
27 30
         res = self.testapp.get('/api/v2/system/applications', status=200)
28 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 37
         assert len(res) == len(applications)
30 38
         for counter, application in enumerate(applications):
31 39
             assert res[counter]['label'] == application.label

+ 26 - 39
backend/tracim_backend/tests/functional/test_user.py View File

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

+ 46 - 42
backend/tracim_backend/tests/functional/test_workspaces.py View File

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

+ 1 - 1
backend/tracim_backend/tests/library/test_content_api.py View File

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

+ 1 - 1
backend/tracim_backend/tests/models/test_content.py View File

@@ -15,7 +15,7 @@ from tracim_backend.models.revision_protection import new_revision
15 15
 from tracim_backend.models import User
16 16
 from tracim_backend.models.data import ActionDescription
17 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 19
 from tracim_backend.models.data import Workspace
20 20
 from tracim_backend.tests import StandardTest
21 21
 

+ 1 - 1
backend/tracim_backend/tests/models/test_content_revision.py View File

@@ -5,7 +5,7 @@ from sqlalchemy import inspect
5 5
 
6 6
 from tracim_backend.models import ContentRevisionRO
7 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 9
 from tracim_backend.tests import DefaultTest
10 10
 from tracim_backend.tests import eq_
11 11
 

+ 2 - 2
backend/tracim_backend/views/contents_api/comment_controller.py View File

@@ -7,7 +7,7 @@ try:  # Python 3.5+
7 7
 except ImportError:
8 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 11
 from tracim_backend.extensions import hapic
12 12
 from tracim_backend.lib.core.content import ContentApi
13 13
 from tracim_backend.lib.core.workspace import WorkspaceApi
@@ -20,7 +20,7 @@ from tracim_backend.views.core_api.schemas import SetCommentSchema
20 20
 from tracim_backend.views.core_api.schemas import WorkspaceAndContentIdPathSchema
21 21
 from tracim_backend.views.core_api.schemas import NoContentSchema
22 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 24
 from tracim_backend.models.revision_protection import new_revision
25 25
 from tracim_backend.models.data import UserRoleInWorkspace
26 26
 

+ 3 - 3
backend/tracim_backend/views/contents_api/file_controller.py View File

@@ -12,7 +12,7 @@ try:  # Python 3.5+
12 12
 except ImportError:
13 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 16
 from tracim_backend.extensions import hapic
17 17
 from tracim_backend.lib.core.content import ContentApi
18 18
 from tracim_backend.views.controllers import Controller
@@ -32,8 +32,8 @@ from tracim_backend.lib.utils.authorization import require_workspace_role
32 32
 from tracim_backend.models.data import UserRoleInWorkspace
33 33
 from tracim_backend.models.context_models import ContentInContext
34 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 37
 from tracim_backend.models.revision_protection import new_revision
38 38
 from tracim_backend.exceptions import EmptyLabelNotAllowed
39 39
 from tracim_backend.exceptions import PageOfPreviewNotFound

+ 3 - 3
backend/tracim_backend/views/contents_api/html_document_controller.py View File

@@ -11,7 +11,7 @@ try:  # Python 3.5+
11 11
 except ImportError:
12 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 15
 from tracim_backend.extensions import hapic
16 16
 from tracim_backend.lib.core.content import ContentApi
17 17
 from tracim_backend.views.controllers import Controller
@@ -26,8 +26,8 @@ from tracim_backend.lib.utils.authorization import require_workspace_role
26 26
 from tracim_backend.exceptions import EmptyLabelNotAllowed
27 27
 from tracim_backend.models.context_models import ContentInContext
28 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 31
 from tracim_backend.models.revision_protection import new_revision
32 32
 
33 33
 SWAGGER_TAG__HTML_DOCUMENT_ENDPOINTS = 'HTML documents'

+ 3 - 3
backend/tracim_backend/views/contents_api/threads_controller.py View File

@@ -10,7 +10,7 @@ try:  # Python 3.5+
10 10
 except ImportError:
11 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 14
 from tracim_backend.extensions import hapic
15 15
 from tracim_backend.lib.core.content import ContentApi
16 16
 from tracim_backend.views.controllers import Controller
@@ -25,8 +25,8 @@ from tracim_backend.lib.utils.authorization import require_workspace_role
25 25
 from tracim_backend.exceptions import EmptyLabelNotAllowed
26 26
 from tracim_backend.models.context_models import ContentInContext
27 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 30
 from tracim_backend.models.revision_protection import new_revision
31 31
 
32 32
 SWAGGER_TAG__THREAD_ENDPOINTS = 'Threads'

+ 10 - 9
backend/tracim_backend/views/core_api/schemas.py View File

@@ -7,10 +7,10 @@ from marshmallow.validate import Range
7 7
 
8 8
 from tracim_backend.lib.utils.utils import DATETIME_FORMAT
9 9
 from tracim_backend.models.auth import Profile
10
-from tracim_backend.models.contents import GlobalStatus
11
-from tracim_backend.models.contents import CONTENT_STATUS
12
-from tracim_backend.models.contents import CONTENT_TYPES
13
-from tracim_backend.models.contents import open_status
10
+from tracim_backend.app_models.contents import GlobalStatus
11
+from tracim_backend.app_models.contents import CONTENT_STATUS
12
+from tracim_backend.app_models.contents import CONTENT_TYPES
13
+from tracim_backend.app_models.contents import open_status
14 14
 from tracim_backend.models.context_models import ActiveContentFilter
15 15
 from tracim_backend.models.context_models import AutocompleteQuery
16 16
 from tracim_backend.models.context_models import ContentIdsQuery
@@ -39,6 +39,7 @@ from tracim_backend.models.context_models import ContentFilter
39 39
 from tracim_backend.models.context_models import LoginCredentials
40 40
 from tracim_backend.models.data import UserRoleInWorkspace
41 41
 from tracim_backend.models.data import ActionDescription
42
+from tracim_backend.app_models.validator import ALL_CONTENT_TYPES_VALIDATOR
42 43
 
43 44
 
44 45
 class UserDigestSchema(marshmallow.Schema):
@@ -357,7 +358,7 @@ class FilterContentQuerySchema(marshmallow.Schema):
357 358
     content_type = marshmallow.fields.String(
358 359
         example=CONTENT_TYPES.Any_SLUG,
359 360
         default=CONTENT_TYPES.Any_SLUG,
360
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug())
361
+        validate=ALL_CONTENT_TYPES_VALIDATOR
361 362
     )
362 363
 
363 364
     @post_load
@@ -607,7 +608,7 @@ class StatusSchema(marshmallow.Schema):
607 608
 class ContentTypeSchema(marshmallow.Schema):
608 609
     slug = marshmallow.fields.String(
609 610
         example='pagehtml',
610
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
611
+        validate=ALL_CONTENT_TYPES_VALIDATOR,
611 612
     )
612 613
     fa_icon = marshmallow.fields.String(
613 614
         example='fa-file-text-o',
@@ -661,7 +662,7 @@ class ContentCreationSchema(marshmallow.Schema):
661 662
     )
662 663
     content_type = marshmallow.fields.String(
663 664
         example='html-document',
664
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
665
+        validate=ALL_CONTENT_TYPES_VALIDATOR,
665 666
     )
666 667
     parent_id = marshmallow.fields.Integer(
667 668
         example=35,
@@ -696,12 +697,12 @@ class ContentDigestSchema(marshmallow.Schema):
696 697
     label = marshmallow.fields.Str(example='Intervention Report 12')
697 698
     content_type = marshmallow.fields.Str(
698 699
         example='html-document',
699
-        validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug()),
700
+        validate=ALL_CONTENT_TYPES_VALIDATOR,
700 701
     )
701 702
     sub_content_types = marshmallow.fields.List(
702 703
         marshmallow.fields.String(
703 704
             example='html-content',
704
-            validate=OneOf(CONTENT_TYPES.endpoint_allowed_types_slug())
705
+            validate=ALL_CONTENT_TYPES_VALIDATOR
705 706
         ),
706 707
         description='list of content types allowed as sub contents. '
707 708
                     'This field is required for folder contents, '

+ 1 - 1
backend/tracim_backend/views/core_api/session_controller.py View File

@@ -5,7 +5,7 @@ try:  # Python 3.5+
5 5
 except ImportError:
6 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 9
 from tracim_backend.extensions import hapic
10 10
 from tracim_backend.lib.core.user import UserApi
11 11
 from tracim_backend.views.controllers import Controller

+ 9 - 5
backend/tracim_backend/views/core_api/system_controller.py View File

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

+ 2 - 2
backend/tracim_backend/views/core_api/user_controller.py View File

@@ -6,7 +6,7 @@ except ImportError:
6 6
     from http import client as HTTPStatus
7 7
 
8 8
 from tracim_backend import hapic
9
-from tracim_backend import TracimRequest
9
+from tracim_backend.lib.utils.request import TracimRequest
10 10
 from tracim_backend.models import Group
11 11
 from tracim_backend.lib.core.group import GroupApi
12 12
 from tracim_backend.lib.core.user import UserApi
@@ -34,7 +34,7 @@ from tracim_backend.views.core_api.schemas import UserWorkspaceAndContentIdPathS
34 34
 from tracim_backend.views.core_api.schemas import ContentDigestSchema
35 35
 from tracim_backend.views.core_api.schemas import ActiveContentFilterQuerySchema
36 36
 from tracim_backend.views.core_api.schemas import WorkspaceDigestSchema
37
-from tracim_backend.models.contents import CONTENT_TYPES
37
+from tracim_backend.app_models.contents import CONTENT_TYPES
38 38
 
39 39
 SWAGGER_TAG__USER_ENDPOINTS = 'Users'
40 40
 

+ 2 - 2
backend/tracim_backend/views/core_api/workspace_controller.py View File

@@ -11,7 +11,7 @@ except ImportError:
11 11
     from http import client as HTTPStatus
12 12
 
13 13
 from tracim_backend import hapic
14
-from tracim_backend import TracimRequest
14
+from tracim_backend.lib.utils.request import TracimRequest
15 15
 from tracim_backend.lib.core.workspace import WorkspaceApi
16 16
 from tracim_backend.lib.core.content import ContentApi
17 17
 from tracim_backend.lib.core.userworkspace import RoleApi
@@ -47,7 +47,7 @@ from tracim_backend.views.core_api.schemas import ContentDigestSchema
47 47
 from tracim_backend.views.core_api.schemas import WorkspaceSchema
48 48
 from tracim_backend.views.core_api.schemas import WorkspaceIdPathSchema
49 49
 from tracim_backend.views.core_api.schemas import WorkspaceMemberSchema
50
-from tracim_backend.models.contents import CONTENT_TYPES
50
+from tracim_backend.app_models.contents import CONTENT_TYPES
51 51
 from tracim_backend.models.revision_protection import new_revision
52 52
 
53 53
 SWAGGER_TAG_WORKSPACE_ENDPOINTS = 'Workspaces'

+ 8 - 2
backend/tracim_backend/views/frontend.py View File

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