瀏覽代碼

Merge pull request #80 from tracim/feature/578_add_api_for_workspace/apps

Bastien Sevajol 6 年之前
父節點
當前提交
fa2ead5b8f
沒有帳戶連結到提交者的電子郵件
共有 35 個文件被更改,包括 1560 次插入181 次删除
  1. 1 0
      setup.py
  2. 11 2
      tracim/__init__.py
  3. 1 0
      tracim/command/user.py
  4. 6 2
      tracim/exceptions.py
  5. 18 3
      tracim/fixtures/content.py
  6. 4 0
      tracim/lib/core/group.py
  7. 16 7
      tracim/lib/core/user.py
  8. 50 20
      tracim/lib/core/userworkspace.py
  9. 20 0
      tracim/lib/core/workspace.py
  10. 1 0
      tracim/lib/mail_notifier/notifier.py
  11. 2 1
      tracim/lib/utils/authentification.py
  12. 22 2
      tracim/lib/utils/authorization.py
  13. 116 53
      tracim/lib/utils/request.py
  14. 10 2
      tracim/lib/webdav/dav_provider.py
  15. 2 2
      tracim/lib/webdav/design.py
  16. 3 1
      tracim/lib/webdav/resources.py
  17. 99 0
      tracim/models/applications.py
  18. 13 4
      tracim/models/auth.py
  19. 137 0
      tracim/models/context_models.py
  20. 33 10
      tracim/models/data.py
  21. 71 0
      tracim/models/workspace_menu_entries.py
  22. 1 0
      tracim/tests/__init__.py
  23. 2 0
      tracim/tests/functional/test_mail_notification.py
  24. 77 0
      tracim/tests/functional/test_system.py
  25. 137 0
      tracim/tests/functional/test_user.py
  26. 218 0
      tracim/tests/functional/test_workspaces.py
  27. 223 61
      tracim/tests/library/test_content_api.py
  28. 4 4
      tracim/tests/library/test_user_api.py
  29. 8 2
      tracim/tests/library/test_workspace.py
  30. 0 0
      tracim/views/core_api/__init__.py
  31. 62 3
      tracim/views/core_api/schemas.py
  32. 2 2
      tracim/views/core_api/session_controller.py
  33. 42 0
      tracim/views/core_api/system_controller.py
  34. 58 0
      tracim/views/core_api/user_controller.py
  35. 90 0
      tracim/views/core_api/workspace_controller.py

+ 1 - 0
setup.py 查看文件

34
     # others
34
     # others
35
     'filedepot',
35
     'filedepot',
36
     'babel',
36
     'babel',
37
+    'python-slugify',
37
     # mail-notifier
38
     # mail-notifier
38
     'mako',
39
     'mako',
39
     'lxml',
40
     'lxml',

+ 11 - 2
tracim/__init__.py 查看文件

18
 from tracim.lib.webdav import WebdavAppFactory
18
 from tracim.lib.webdav import WebdavAppFactory
19
 from tracim.views import BASE_API_V2
19
 from tracim.views import BASE_API_V2
20
 from tracim.views.core_api.session_controller import SessionController
20
 from tracim.views.core_api.session_controller import SessionController
21
+from tracim.views.core_api.system_controller import SystemController
22
+from tracim.views.core_api.user_controller import UserController
23
+from tracim.views.core_api.workspace_controller import WorkspaceController
21
 from tracim.views.errors import ErrorSchema
24
 from tracim.views.errors import ErrorSchema
22
 from tracim.lib.utils.cors import add_cors_support
25
 from tracim.lib.utils.cors import add_cors_support
23
 
26
 
64
     context.handle_exception(OperationalError, 500)
67
     context.handle_exception(OperationalError, 500)
65
     context.handle_exception(Exception, 500)
68
     context.handle_exception(Exception, 500)
66
     # Add controllers
69
     # Add controllers
67
-    session_api = SessionController()
68
-    configurator.include(session_api.bind, route_prefix=BASE_API_V2)
70
+    session_controller = SessionController()
71
+    system_controller = SystemController()
72
+    user_controller = UserController()
73
+    workspace_controller = WorkspaceController()
74
+    configurator.include(session_controller.bind, route_prefix=BASE_API_V2)
75
+    configurator.include(system_controller.bind, route_prefix=BASE_API_V2)
76
+    configurator.include(user_controller.bind, route_prefix=BASE_API_V2)
77
+    configurator.include(workspace_controller.bind, route_prefix=BASE_API_V2)
69
     hapic.add_documentation_view(
78
     hapic.add_documentation_view(
70
         '/api/v2/doc',
79
         '/api/v2/doc',
71
         'Tracim v2 API',
80
         'Tracim v2 API',

+ 1 - 0
tracim/command/user.py 查看文件

165
         self._group_api = GroupApi(
165
         self._group_api = GroupApi(
166
             current_user=None,
166
             current_user=None,
167
             session=self._session,
167
             session=self._session,
168
+            config=self._app_config,
168
         )
169
         )
169
         user = self._proceed_user(parsed_args)
170
         user = self._proceed_user(parsed_args)
170
         self._proceed_groups(user, parsed_args)
171
         self._proceed_groups(user, parsed_args)

+ 6 - 2
tracim/exceptions.py 查看文件

61
     pass
61
     pass
62
 
62
 
63
 
63
 
64
-class NotAuthentificated(TracimException):
64
+class NotAuthenticated(TracimException):
65
     pass
65
     pass
66
 
66
 
67
 
67
 
93
     pass
93
     pass
94
 
94
 
95
 
95
 
96
-class UserNotExist(TracimException):
96
+class UserDoesNotExist(TracimException):
97
+    pass
98
+
99
+
100
+class UserNotFoundInTracimRequest(TracimException):
97
     pass
101
     pass
98
 
102
 
99
 
103
 

+ 18 - 3
tracim/fixtures/content.py 查看文件

24
         admin_workspace_api = WorkspaceApi(
24
         admin_workspace_api = WorkspaceApi(
25
             current_user=admin,
25
             current_user=admin,
26
             session=self._session,
26
             session=self._session,
27
+            config=self._config,
27
         )
28
         )
28
         bob_workspace_api = WorkspaceApi(
29
         bob_workspace_api = WorkspaceApi(
29
             current_user=bob,
30
             current_user=bob,
30
             session=self._session,
31
             session=self._session,
32
+            config=self._config
31
         )
33
         )
32
         content_api = ContentApi(
34
         content_api = ContentApi(
33
             current_user=admin,
35
             current_user=admin,
37
         role_api = RoleApi(
39
         role_api = RoleApi(
38
             current_user=admin,
40
             current_user=admin,
39
             session=self._session,
41
             session=self._session,
42
+            config=self._config,
40
         )
43
         )
41
 
44
 
42
         # Workspaces
45
         # Workspaces
43
-        w1 = admin_workspace_api.create_workspace('w1', save_now=True)
44
-        w2 = bob_workspace_api.create_workspace('w2', save_now=True)
45
-        w3 = admin_workspace_api.create_workspace('w3', save_now=True)
46
+        w1 = admin_workspace_api.create_workspace(
47
+            'w1',
48
+            description='This is a workspace',
49
+            save_now=True
50
+        )
51
+        w2 = bob_workspace_api.create_workspace(
52
+            'w2',
53
+            description='A great workspace',
54
+            save_now=True
55
+        )
56
+        w3 = admin_workspace_api.create_workspace(
57
+            'w3',
58
+            description='Just another workspace',
59
+            save_now=True
60
+        )
46
 
61
 
47
         # Workspaces roles
62
         # Workspaces roles
48
         role_api.create_one(
63
         role_api.create_one(

+ 4 - 0
tracim/lib/core/group.py 查看文件

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
 import typing
2
 import typing
3
 
3
 
4
+from tracim import CFG
5
+
4
 __author__ = 'damien'
6
 __author__ = 'damien'
5
 
7
 
6
 from tracim.models.auth import Group, User
8
 from tracim.models.auth import Group, User
14
             self,
16
             self,
15
             session: Session,
17
             session: Session,
16
             current_user: typing.Optional[User],
18
             current_user: typing.Optional[User],
19
+            config: CFG
17
     ):
20
     ):
18
         self._user = current_user
21
         self._user = current_user
19
         self._session = session
22
         self._session = session
23
+        self._config = config
20
 
24
 
21
     def _base_query(self) -> Query:
25
     def _base_query(self) -> Query:
22
         return self._session.query(Group)
26
         return self._session.query(Group)

+ 16 - 7
tracim/lib/core/user.py 查看文件

11
 
11
 
12
 from tracim import CFG
12
 from tracim import CFG
13
 from tracim.models.auth import User
13
 from tracim.models.auth import User
14
+from tracim.models.auth import Group
14
 from sqlalchemy.orm.exc import NoResultFound
15
 from sqlalchemy.orm.exc import NoResultFound
15
-from tracim.exceptions import WrongUserPassword, UserNotExist
16
+from tracim.exceptions import WrongUserPassword, UserDoesNotExist
16
 from tracim.exceptions import AuthenticationFailed
17
 from tracim.exceptions import AuthenticationFailed
17
 from tracim.models.context_models import UserInContext
18
 from tracim.models.context_models import UserInContext
18
 
19
 
49
         """
50
         """
50
         Get one user by user id
51
         Get one user by user id
51
         """
52
         """
52
-        return self._base_query().filter(User.user_id == user_id).one()
53
+        try:
54
+            user = self._base_query().filter(User.user_id == user_id).one()
55
+        except NoResultFound as exc:
56
+            raise UserDoesNotExist('User "{}" not found in database'.format(user_id)) from exc  # nopep8
57
+        return user
53
 
58
 
54
     def get_one_by_email(self, email: str) -> User:
59
     def get_one_by_email(self, email: str) -> User:
55
         """
60
         """
57
         :param email: Email of the user
62
         :param email: Email of the user
58
         :return: one user
63
         :return: one user
59
         """
64
         """
60
-        return self._base_query().filter(User.email == email).one()
65
+        try:
66
+            user = self._base_query().filter(User.email == email).one()
67
+        except NoResultFound as exc:
68
+            raise UserDoesNotExist('User "{}" not found in database'.format(email)) from exc  # nopep8
69
+        return user
61
 
70
 
62
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
71
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
63
     def get_one_by_id(self, id: int) -> User:
72
     def get_one_by_id(self, id: int) -> User:
68
         Get current_user
77
         Get current_user
69
         """
78
         """
70
         if not self._user:
79
         if not self._user:
71
-            raise UserNotExist()
80
+            raise UserDoesNotExist('There is no current user')
72
         return self._user
81
         return self._user
73
 
82
 
74
     def get_all(self) -> typing.Iterable[User]:
83
     def get_all(self) -> typing.Iterable[User]:
97
             if user.validate_password(password):
106
             if user.validate_password(password):
98
                 return user
107
                 return user
99
             else:
108
             else:
100
-                raise WrongUserPassword()
101
-        except (WrongUserPassword, NoResultFound):
102
-            raise AuthenticationFailed()
109
+                raise WrongUserPassword('User "{}" password is incorrect'.format(email))  # nopep8
110
+        except (WrongUserPassword, UserDoesNotExist) as exc:
111
+            raise AuthenticationFailed('User "{}" authentication failed'.format(email)) from exc  # nopep8
103
 
112
 
104
     # Actions
113
     # Actions
105
 
114
 

+ 50 - 20
tracim/lib/core/userworkspace.py 查看文件

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
 import typing
2
 import typing
3
 
3
 
4
+from tracim import CFG
5
+from tracim.models.context_models import UserRoleWorkspaceInContext
6
+
4
 __author__ = 'damien'
7
 __author__ = 'damien'
5
 
8
 
6
 from sqlalchemy.orm import Session
9
 from sqlalchemy.orm import Session
10
+from sqlalchemy.orm import Query
7
 from tracim.models.auth import User
11
 from tracim.models.auth import User
8
 from tracim.models.data import Workspace
12
 from tracim.models.data import Workspace
9
 from tracim.models.data import UserRoleInWorkspace
13
 from tracim.models.data import UserRoleInWorkspace
38
         ],
42
         ],
39
     }
43
     }
40
 
44
 
45
+    def get_user_role_workspace_with_context(
46
+            self,
47
+            user_role: UserRoleInWorkspace
48
+    ) -> UserRoleWorkspaceInContext:
49
+        """
50
+        Return WorkspaceInContext object from Workspace
51
+        """
52
+        assert self._config
53
+        workspace = UserRoleWorkspaceInContext(
54
+            user_role=user_role,
55
+            dbsession=self._session,
56
+            config=self._config,
57
+        )
58
+        return workspace
59
+
41
     @classmethod
60
     @classmethod
42
     def role_can_read_member_role(cls, reader_role: int, tested_role: int) \
61
     def role_can_read_member_role(cls, reader_role: int, tested_role: int) \
43
             -> bool:
62
             -> bool:
56
 
75
 
57
         return role
76
         return role
58
 
77
 
59
-    def __init__(self, session: Session, current_user: typing.Optional[User]):
78
+    def __init__(
79
+        self,
80
+        session: Session,
81
+        current_user: typing.Optional[User],
82
+        config: CFG,
83
+    )-> None:
60
         self._session = session
84
         self._session = session
61
         self._user = current_user
85
         self._user = current_user
86
+        self._config = config
62
 
87
 
63
-    def _get_one_rsc(self, user_id, workspace_id):
88
+    def _get_one_rsc(self, user_id: int, workspace_id: int) -> Query:
64
         """
89
         """
65
         :param user_id:
90
         :param user_id:
66
         :param workspace_id:
91
         :param workspace_id:
70
             filter(UserRoleInWorkspace.workspace_id == workspace_id).\
95
             filter(UserRoleInWorkspace.workspace_id == workspace_id).\
71
             filter(UserRoleInWorkspace.user_id == user_id)
96
             filter(UserRoleInWorkspace.user_id == user_id)
72
 
97
 
73
-    def get_one(self, user_id, workspace_id):
98
+    def get_one(self, user_id: int, workspace_id: int) -> UserRoleInWorkspace:
74
         return self._get_one_rsc(user_id, workspace_id).one()
99
         return self._get_one_rsc(user_id, workspace_id).one()
75
 
100
 
76
     def create_one(
101
     def create_one(
77
-            self,
78
-            user: User,
79
-            workspace: Workspace,
80
-            role_level: int,
81
-            with_notif: bool,
82
-            flush: bool=True
102
+        self,
103
+        user: User,
104
+        workspace: Workspace,
105
+        role_level: int,
106
+        with_notif: bool,
107
+        flush: bool=True
83
     ) -> UserRoleInWorkspace:
108
     ) -> UserRoleInWorkspace:
84
         role = self.create_role()
109
         role = self.create_role()
85
         role.user_id = user.user_id
110
         role.user_id = user.user_id
90
             self._session.flush()
115
             self._session.flush()
91
         return role
116
         return role
92
 
117
 
93
-    def delete_one(self, user_id, workspace_id, flush=True):
118
+    def delete_one(self, user_id: int, workspace_id: int, flush=True) -> None:
94
         self._get_one_rsc(user_id, workspace_id).delete()
119
         self._get_one_rsc(user_id, workspace_id).delete()
95
         if flush:
120
         if flush:
96
             self._session.flush()
121
             self._session.flush()
97
 
122
 
98
-    def _get_all_for_user(self, user_id):
123
+    def _get_all_for_user(self, user_id) -> typing.List[UserRoleInWorkspace]:
99
         return self._session.query(UserRoleInWorkspace)\
124
         return self._session.query(UserRoleInWorkspace)\
100
             .filter(UserRoleInWorkspace.user_id == user_id)
125
             .filter(UserRoleInWorkspace.user_id == user_id)
101
 
126
 
102
-    def get_all_for_user(self, user_id):
103
-        return self._get_all_for_user(user_id).all()
127
+    def get_all_for_user(self, user: User) -> typing.List[UserRoleInWorkspace]:
128
+        return self._get_all_for_user(user.user_id).all()
104
 
129
 
105
     def get_all_for_user_order_by_workspace(
130
     def get_all_for_user_order_by_workspace(
106
-            self,
107
-            user_id: int
108
-    ) -> UserRoleInWorkspace:
131
+        self,
132
+        user_id: int
133
+    ) -> typing.List[UserRoleInWorkspace]:
109
         return self._get_all_for_user(user_id)\
134
         return self._get_all_for_user(user_id)\
110
             .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()
135
             .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()
111
 
136
 
112
-    def get_all_for_workspace(self, workspace_id):
137
+    def get_all_for_workspace(
138
+        self,
139
+        workspace:Workspace
140
+    ) -> typing.List[UserRoleInWorkspace]:
113
         return self._session.query(UserRoleInWorkspace)\
141
         return self._session.query(UserRoleInWorkspace)\
114
-            .filter(UserRoleInWorkspace.workspace_id == workspace_id).all()
142
+            .filter(UserRoleInWorkspace.workspace_id==workspace.workspace_id)\
143
+            .all()
115
 
144
 
116
-    def save(self, role: UserRoleInWorkspace):
145
+    def save(self, role: UserRoleInWorkspace) -> None:
117
         self._session.flush()
146
         self._session.flush()
118
 
147
 
148
+    # TODO - G.M - 07-06-2018 - [Cleanup] Check if this method is already needed
119
     @classmethod
149
     @classmethod
120
-    def get_roles_for_select_field(cls):
150
+    def get_roles_for_select_field(cls) -> typing.List[RoleType]:
121
         """
151
         """
122
 
152
 
123
         :return: list of DictLikeClass instances representing available Roles
153
         :return: list of DictLikeClass instances representing available Roles

+ 20 - 0
tracim/lib/core/workspace.py 查看文件

3
 
3
 
4
 from sqlalchemy.orm import Query
4
 from sqlalchemy.orm import Query
5
 from sqlalchemy.orm import Session
5
 from sqlalchemy.orm import Session
6
+
7
+from tracim import CFG
6
 from tracim.lib.utils.translation import fake_translator as _
8
 from tracim.lib.utils.translation import fake_translator as _
7
 
9
 
8
 from tracim.lib.core.userworkspace import RoleApi
10
 from tracim.lib.core.userworkspace import RoleApi
9
 from tracim.models.auth import Group
11
 from tracim.models.auth import Group
10
 from tracim.models.auth import User
12
 from tracim.models.auth import User
13
+from tracim.models.context_models import WorkspaceInContext
11
 from tracim.models.data import UserRoleInWorkspace
14
 from tracim.models.data import UserRoleInWorkspace
12
 from tracim.models.data import Workspace
15
 from tracim.models.data import Workspace
13
 
16
 
20
             self,
23
             self,
21
             session: Session,
24
             session: Session,
22
             current_user: User,
25
             current_user: User,
26
+            config: CFG,
23
             force_role: bool=False
27
             force_role: bool=False
24
     ):
28
     ):
25
         """
29
         """
28
         """
32
         """
29
         self._session = session
33
         self._session = session
30
         self._user = current_user
34
         self._user = current_user
35
+        self._config = config
31
         self._force_role = force_role
36
         self._force_role = force_role
32
 
37
 
33
     def _base_query_without_roles(self):
38
     def _base_query_without_roles(self):
42
             filter(UserRoleInWorkspace.user_id == self._user.user_id).\
47
             filter(UserRoleInWorkspace.user_id == self._user.user_id).\
43
             filter(Workspace.is_deleted == False)
48
             filter(Workspace.is_deleted == False)
44
 
49
 
50
+    def get_workspace_with_context(
51
+            self,
52
+            workspace: Workspace
53
+    ) -> WorkspaceInContext:
54
+        """
55
+        Return WorkspaceInContext object from Workspace
56
+        """
57
+        workspace = WorkspaceInContext(
58
+            workspace=workspace,
59
+            dbsession=self._session,
60
+            config=self._config,
61
+        )
62
+        return workspace
63
+
45
     def create_workspace(
64
     def create_workspace(
46
             self,
65
             self,
47
             label: str='',
66
             label: str='',
62
         role_api = RoleApi(
81
         role_api = RoleApi(
63
             session=self._session,
82
             session=self._session,
64
             current_user=self._user,
83
             current_user=self._user,
84
+            config=self._config
65
         )
85
         )
66
 
86
 
67
         role = role_api.create_one(
87
         role = role_api.create_one(

+ 1 - 0
tracim/lib/mail_notifier/notifier.py 查看文件

238
         notifiable_roles = WorkspaceApi(
238
         notifiable_roles = WorkspaceApi(
239
             current_user=user,
239
             current_user=user,
240
             session=self.session,
240
             session=self.session,
241
+            config=self.config,
241
         ).get_notifiable_roles(content.workspace)
242
         ).get_notifiable_roles(content.workspace)
242
 
243
 
243
         if len(notifiable_roles) <= 0:
244
         if len(notifiable_roles) <= 0:

+ 2 - 1
tracim/lib/utils/authentification.py 查看文件

4
 from sqlalchemy.orm.exc import NoResultFound
4
 from sqlalchemy.orm.exc import NoResultFound
5
 
5
 
6
 from tracim import TracimRequest
6
 from tracim import TracimRequest
7
+from tracim.exceptions import UserDoesNotExist
7
 from tracim.lib.core.user import UserApi
8
 from tracim.lib.core.user import UserApi
8
 from tracim.models import User
9
 from tracim.models import User
9
 
10
 
50
         if not login:
51
         if not login:
51
             return None
52
             return None
52
         user = uapi.get_one_by_email(login)
53
         user = uapi.get_one_by_email(login)
53
-    except NoResultFound:
54
+    except UserDoesNotExist:
54
         return None
55
         return None
55
     return user
56
     return user

+ 22 - 2
tracim/lib/utils/authorization.py 查看文件

44
 # We prefer to use decorators
44
 # We prefer to use decorators
45
 
45
 
46
 
46
 
47
-def require_profile(group):
47
+def require_same_user_or_profile(group: int):
48
+    """
49
+    Decorator for view to restrict access of tracim request if candidate user
50
+    is distinct from authenticated user and not with high enough profile.
51
+    :param group: value from Group Object
52
+    like Group.TIM_USER or Group.TIM_MANAGER
53
+    :return:
54
+    """
55
+    def decorator(func):
56
+        def wrapper(self, context, request: 'TracimRequest'):
57
+            auth_user = request.current_user
58
+            candidate_user = request.candidate_user
59
+            if auth_user.user_id == candidate_user.user_id or \
60
+                    auth_user.profile.id >= group:
61
+                return func(self, context, request)
62
+            raise InsufficientUserProfile()
63
+        return wrapper
64
+    return decorator
65
+
66
+
67
+def require_profile(group: int):
48
     """
68
     """
49
     Decorator for view to restrict access of tracim request if profile is
69
     Decorator for view to restrict access of tracim request if profile is
50
     not high enough
70
     not high enough
62
     return decorator
82
     return decorator
63
 
83
 
64
 
84
 
65
-def require_workspace_role(minimal_required_role):
85
+def require_workspace_role(minimal_required_role: int):
66
     """
86
     """
67
     Decorator for view to restrict access of tracim request if role
87
     Decorator for view to restrict access of tracim request if role
68
     is not high enough
88
     is not high enough

+ 116 - 53
tracim/lib/utils/request.py 查看文件

1
-import typing
1
+# -*- coding: utf-8 -*-
2
 from pyramid.request import Request
2
 from pyramid.request import Request
3
 from sqlalchemy.orm.exc import NoResultFound
3
 from sqlalchemy.orm.exc import NoResultFound
4
 
4
 
5
-from tracim.exceptions import NotAuthentificated
5
+from tracim.exceptions import NotAuthenticated
6
+from tracim.exceptions import UserNotFoundInTracimRequest
7
+from tracim.exceptions import UserDoesNotExist
6
 from tracim.exceptions import WorkspaceNotFound
8
 from tracim.exceptions import WorkspaceNotFound
7
 from tracim.exceptions import ImmutableAttribute
9
 from tracim.exceptions import ImmutableAttribute
8
 from tracim.lib.core.user import UserApi
10
 from tracim.lib.core.user import UserApi
32
             decode_param_names,
34
             decode_param_names,
33
             **kw
35
             **kw
34
         )
36
         )
37
+        # Current workspace, found by request headers or content
35
         self._current_workspace = None  # type: Workspace
38
         self._current_workspace = None  # type: Workspace
39
+
40
+        # Authenticated user
36
         self._current_user = None  # type: User
41
         self._current_user = None  # type: User
42
+
43
+        # User found from request headers, content, distinct from authenticated
44
+        # user
45
+        self._candidate_user = None  # type: User
46
+
37
         # INFO - G.M - 18-05-2018 - Close db at the end of the request
47
         # INFO - G.M - 18-05-2018 - Close db at the end of the request
38
         self.add_finished_callback(self._cleanup)
48
         self.add_finished_callback(self._cleanup)
39
 
49
 
46
         :return: Workspace of the request
56
         :return: Workspace of the request
47
         """
57
         """
48
         if self._current_workspace is None:
58
         if self._current_workspace is None:
49
-            self.current_workspace = get_workspace(self.current_user, self)
59
+            self.current_workspace = self._get_workspace(self.current_user, self)
50
         return self._current_workspace
60
         return self._current_workspace
51
 
61
 
52
     @current_workspace.setter
62
     @current_workspace.setter
64
 
74
 
65
     @property
75
     @property
66
     def current_user(self) -> User:
76
     def current_user(self) -> User:
77
+        """
78
+        Get user from authentication mecanism.
79
+        """
67
         if self._current_user is None:
80
         if self._current_user is None:
68
-            self.current_user = get_safe_user(self)
81
+            self.current_user = self._get_auth_safe_user(self)
69
         return self._current_user
82
         return self._current_user
70
 
83
 
71
     @current_user.setter
84
     @current_user.setter
76
             )
89
             )
77
         self._current_user = user
90
         self._current_user = user
78
 
91
 
92
+    # TODO - G.M - 24-05-2018 - Find a better naming for this ?
93
+    @property
94
+    def candidate_user(self) -> User:
95
+        """
96
+        Get user from headers/body request. This user is not
97
+        the one found by authentication mecanism. This user
98
+        can help user to know about who one page is about in
99
+        a similar way as current_workspace.
100
+        """
101
+        if self._candidate_user is None:
102
+            self.candidate_user = self._get_candidate_user(self)
103
+        return self._candidate_user
104
+
79
     def _cleanup(self, request: 'TracimRequest') -> None:
105
     def _cleanup(self, request: 'TracimRequest') -> None:
80
         """
106
         """
81
         Close dbsession at the end of the request in order to avoid exception
107
         Close dbsession at the end of the request in order to avoid exception
89
         self._current_workspace = None
115
         self._current_workspace = None
90
         self.dbsession.close()
116
         self.dbsession.close()
91
 
117
 
92
-###
93
-# Utils for TracimRequest
94
-###
95
 
118
 
96
-def get_safe_user(
97
-        request: TracimRequest,
98
-) -> User:
99
-    """
100
-    Get current pyramid authenticated user from request
101
-    :param request: pyramid request
102
-    :return: current authenticated user
103
-    """
104
-    app_config = request.registry.settings['CFG']
105
-    uapi = UserApi(None, session=request.dbsession, config=app_config)
106
-    try:
107
-        login = request.authenticated_userid
108
-        if not login:
109
-            raise NotAuthentificated('not authenticated user_id,'
110
-                                     'Failed Authentification ?')
111
-        user = uapi.get_one_by_email(login)
112
-    except NoResultFound:
113
-        raise NotAuthentificated('User not found')
114
-    return user
115
-
116
-
117
-def get_workspace(
118
-        user: User,
119
-        request: TracimRequest
120
-) -> Workspace:
121
-    """
122
-    Get current workspace from request
123
-    :param user: User who want to check the workspace
124
-    :param request: pyramid request
125
-    :return: current workspace
126
-    """
127
-    workspace_id = ''
128
-    try:
129
-        if 'workspace_id' not in request.json_body:
130
-            raise WorkspaceNotFound('No workspace_id param in json body')
131
-        workspace_id = request.json_body['workspace_id']
132
-        wapi = WorkspaceApi(current_user=user, session=request.dbsession)
133
-        workspace = wapi.get_one(workspace_id)
134
-    except JSONDecodeError:
135
-        raise WorkspaceNotFound('Bad json body')
136
-    except NoResultFound:
137
-        raise WorkspaceNotFound(
138
-            'Workspace {} does not exist '
139
-            'or is not visible for this user'.format(workspace_id)
140
-        )
141
-    return workspace
119
+    @candidate_user.setter
120
+    def candidate_user(self, user: User) -> None:
121
+        if self._candidate_user is not None:
122
+            raise ImmutableAttribute(
123
+                "Can't modify already setted candidate_user"
124
+            )
125
+        self._candidate_user = user
126
+
127
+    ###
128
+    # Utils for TracimRequest
129
+    ###
130
+
131
+    def _get_candidate_user(
132
+            self,
133
+            request: 'TracimRequest',
134
+    ) -> User:
135
+        """
136
+        Get candidate user
137
+        :param request: pyramid request
138
+        :return: user found from header/body
139
+        """
140
+        app_config = request.registry.settings['CFG']
141
+        uapi = UserApi(None, session=request.dbsession, config=app_config)
142
+
143
+        try:
144
+            login = None
145
+            if 'user_id' in request.matchdict:
146
+                login = request.matchdict['user_id']
147
+            if not login:
148
+                raise UserNotFoundInTracimRequest('You request a candidate user but the context not permit to found one')  # nopep8
149
+            user = uapi.get_one(login)
150
+        except UserNotFoundInTracimRequest as exc:
151
+            raise UserDoesNotExist('User {} not found'.format(login)) from exc
152
+        return user
153
+
154
+    def _get_auth_safe_user(
155
+            self,
156
+            request: 'TracimRequest',
157
+    ) -> User:
158
+        """
159
+        Get current pyramid authenticated user from request
160
+        :param request: pyramid request
161
+        :return: current authenticated user
162
+        """
163
+        app_config = request.registry.settings['CFG']
164
+        uapi = UserApi(None, session=request.dbsession, config=app_config)
165
+        try:
166
+            login = request.authenticated_userid
167
+            if not login:
168
+                raise UserNotFoundInTracimRequest('You request a current user but the context not permit to found one')  # nopep8
169
+            user = uapi.get_one_by_email(login)
170
+        except (UserDoesNotExist, UserNotFoundInTracimRequest) as exc:
171
+            raise NotAuthenticated('User {} not found'.format(login)) from exc
172
+        return user
173
+
174
+    def _get_workspace(
175
+            self,
176
+            user: User,
177
+            request: 'TracimRequest'
178
+    ) -> Workspace:
179
+        """
180
+        Get current workspace from request
181
+        :param user: User who want to check the workspace
182
+        :param request: pyramid request
183
+        :return: current workspace
184
+        """
185
+        workspace_id = ''
186
+        try:
187
+            if 'workspace_id' in request.matchdict:
188
+                workspace_id = request.matchdict['workspace_id']
189
+            if not workspace_id:
190
+                raise WorkspaceNotFound('No workspace_id property found in request')
191
+            wapi = WorkspaceApi(
192
+                current_user=user,
193
+                session=request.dbsession,
194
+                config=request.registry.settings['CFG']
195
+            )
196
+            workspace = wapi.get_one(workspace_id)
197
+        except JSONDecodeError:
198
+            raise WorkspaceNotFound('Bad json body')
199
+        except NoResultFound:
200
+            raise WorkspaceNotFound(
201
+                'Workspace {} does not exist '
202
+                'or is not visible for this user'.format(workspace_id)
203
+            )
204
+        return workspace

+ 10 - 2
tracim/lib/webdav/dav_provider.py 查看文件

72
         if path == root_path:
72
         if path == root_path:
73
             return resources.RootResource(path, environ, user=user, session=session)
73
             return resources.RootResource(path, environ, user=user, session=session)
74
 
74
 
75
-        workspace_api = WorkspaceApi(current_user=user, session=session)
75
+        workspace_api = WorkspaceApi(
76
+            current_user=user,
77
+            session=session,
78
+            config=self.app_config,
79
+        )
76
         workspace = self.get_workspace_from_path(path, workspace_api)
80
         workspace = self.get_workspace_from_path(path, workspace_api)
77
 
81
 
78
         # If the request path is in the form root/name, then we return a WorkspaceResource resource
82
         # If the request path is in the form root/name, then we return a WorkspaceResource resource
194
 
198
 
195
         workspace = self.get_workspace_from_path(
199
         workspace = self.get_workspace_from_path(
196
             path,
200
             path,
197
-            WorkspaceApi(current_user=user, session=session)
201
+            WorkspaceApi(
202
+                current_user=user,
203
+                session=session,
204
+                config=self.app_config,
205
+            )
198
         )
206
         )
199
 
207
 
200
         if parent_path == root_path or workspace is None:
208
         if parent_path == root_path or workspace is None:

+ 2 - 2
tracim/lib/webdav/design.py 查看文件

164
                     <td>%s</td>
164
                     <td>%s</td>
165
                 </tr>
165
                 </tr>
166
                 ''' % ('warning' if event.id == content_revision.revision_id else '',
166
                 ''' % ('warning' if event.id == content_revision.revision_id else '',
167
-                       event.type.icon,
167
+                       event.type.fa_icon,
168
                        label,
168
                        label,
169
                        date,
169
                        date,
170
                        event.owner.display_name,
170
                        event.owner.display_name,
282
                         </div>
282
                         </div>
283
                     </div>
283
                     </div>
284
                     ''' % ('warning' if t.id == content_revision.revision_id else '',
284
                     ''' % ('warning' if t.id == content_revision.revision_id else '',
285
-                           t.type.icon,
285
+                           t.type.fa_icon,
286
                            t.owner.display_name,
286
                            t.owner.display_name,
287
                            t.create_readable_date(),
287
                            t.create_readable_date(),
288
                            label,
288
                            label,

+ 3 - 1
tracim/lib/webdav/resources.py 查看文件

90
         self.workspace_api = WorkspaceApi(
90
         self.workspace_api = WorkspaceApi(
91
             current_user=self.user,
91
             current_user=self.user,
92
             session=session,
92
             session=session,
93
-            force_role=True
93
+            force_role=True,
94
+            config=self.provider.app_config
94
         )
95
         )
95
 
96
 
96
     def __repr__(self) -> str:
97
     def __repr__(self) -> str:
1254
             workspace_api = WorkspaceApi(
1255
             workspace_api = WorkspaceApi(
1255
                 current_user=self.user,
1256
                 current_user=self.user,
1256
                 session=self.session,
1257
                 session=self.session,
1258
+                config=self.provider.app_config,
1257
                 )
1259
                 )
1258
             content_api = ContentApi(
1260
             content_api = ContentApi(
1259
                 current_user=self.user,
1261
                 current_user=self.user,

+ 99 - 0
tracim/models/applications.py 查看文件

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
+
40
+# default apps
41
+calendar = Application(
42
+    label='Calendar',
43
+    slug='calendar',
44
+    fa_icon='calendar-alt',
45
+    hexcolor='#757575',
46
+    is_active=True,
47
+    config={},
48
+    main_route='/#/workspaces/{workspace_id}/calendar',
49
+)
50
+
51
+thread = Application(
52
+    label='Threads',
53
+    slug='contents/threads',
54
+    fa_icon='comments-o',
55
+    hexcolor='#ad4cf9',
56
+    is_active=True,
57
+    config={},
58
+    main_route='/#/workspaces/{workspace_id}/contents?type=thread',
59
+
60
+)
61
+
62
+_file = Application(
63
+    label='Files',
64
+    slug='contents/files',
65
+    fa_icon='paperclip',
66
+    hexcolor='#FF9900',
67
+    is_active=True,
68
+    config={},
69
+    main_route='/#/workspaces/{workspace_id}/contents?type=file',
70
+)
71
+
72
+markdownpluspage = Application(
73
+    label='Markdown Plus Documents',  # TODO - G.M - 24-05-2018 - Check label
74
+    slug='contents/markdownpluspage',
75
+    fa_icon='file-code',
76
+    hexcolor='#f12d2d',
77
+    is_active=True,
78
+    config={},
79
+    main_route='/#/workspaces/{workspace_id}/contents?type=markdownpluspage',
80
+)
81
+
82
+htmlpage = Application(
83
+    label='Text Documents',  # TODO - G.M - 24-05-2018 - Check label
84
+    slug='contents/htmlpage',
85
+    fa_icon='file-text-o',
86
+    hexcolor='#3f52e3',
87
+    is_active=True,
88
+    config={},
89
+    main_route='/#/workspaces/{workspace_id}/contents?type=htmlpage',
90
+)
91
+# TODO - G.M - 08-06-2018 - This is hardcoded lists of app, make this dynamic.
92
+# List of applications
93
+applications = [
94
+    htmlpage,
95
+    markdownpluspage,
96
+    _file,
97
+    thread,
98
+    calendar,
99
+]

+ 13 - 4
tracim/models/auth.py 查看文件

91
 class Profile(object):
91
 class Profile(object):
92
     """This model is the "max" group associated to a given user."""
92
     """This model is the "max" group associated to a given user."""
93
 
93
 
94
-    _NAME = [Group.TIM_NOBODY_GROUPNAME,
95
-             Group.TIM_USER_GROUPNAME,
96
-             Group.TIM_MANAGER_GROUPNAME,
97
-             Group.TIM_ADMIN_GROUPNAME]
94
+    _NAME = [
95
+        Group.TIM_NOBODY_GROUPNAME,
96
+        Group.TIM_USER_GROUPNAME,
97
+        Group.TIM_MANAGER_GROUPNAME,
98
+        Group.TIM_ADMIN_GROUPNAME,
99
+    ]
100
+
101
+    _IDS = [
102
+        Group.TIM_NOBODY,
103
+        Group.TIM_USER,
104
+        Group.TIM_MANAGER,
105
+        Group.TIM_ADMIN,
106
+    ]
98
 
107
 
99
     # TODO - G.M - 18-04-2018 [Cleanup] Drop this
108
     # TODO - G.M - 18-04-2018 [Cleanup] Drop this
100
     # _LABEL = [l_('Nobody'),
109
     # _LABEL = [l_('Nobody'),

+ 137 - 0
tracim/models/context_models.py 查看文件

2
 import typing
2
 import typing
3
 from datetime import datetime
3
 from datetime import datetime
4
 
4
 
5
+from slugify import slugify
5
 from sqlalchemy.orm import Session
6
 from sqlalchemy.orm import Session
6
 from tracim import CFG
7
 from tracim import CFG
7
 from tracim.models import User
8
 from tracim.models import User
8
 from tracim.models.auth import Profile
9
 from tracim.models.auth import Profile
10
+from tracim.models.data import Workspace, UserRoleInWorkspace
11
+from tracim.models.workspace_menu_entries import default_workspace_menu_entry
12
+from tracim.models.workspace_menu_entries import WorkspaceMenuEntry
9
 
13
 
10
 
14
 
11
 class LoginCredentials(object):
15
 class LoginCredentials(object):
74
     def avatar_url(self) -> typing.Optional[str]:
78
     def avatar_url(self) -> typing.Optional[str]:
75
         # TODO - G-M - 20-04-2018 - [Avatar] Add user avatar feature
79
         # TODO - G-M - 20-04-2018 - [Avatar] Add user avatar feature
76
         return None
80
         return None
81
+
82
+
83
+class WorkspaceInContext(object):
84
+    """
85
+    Interface to get Workspace data and Workspace data related to context.
86
+    """
87
+
88
+    def __init__(self, workspace: Workspace, dbsession: Session, config: CFG):
89
+        self.workspace = workspace
90
+        self.dbsession = dbsession
91
+        self.config = config
92
+
93
+    @property
94
+    def workspace_id(self) -> int:
95
+        """
96
+        numeric id of the workspace.
97
+        """
98
+        return self.workspace.workspace_id
99
+
100
+    @property
101
+    def id(self) -> int:
102
+        """
103
+        alias of workspace_id
104
+        """
105
+        return self.workspace_id
106
+
107
+    @property
108
+    def label(self) -> str:
109
+        """
110
+        get workspace label
111
+        """
112
+        return self.workspace.label
113
+
114
+    @property
115
+    def description(self) -> str:
116
+        """
117
+        get workspace description
118
+        """
119
+        return self.workspace.description
120
+
121
+    @property
122
+    def slug(self) -> str:
123
+        """
124
+        get workspace slug
125
+        """
126
+        return slugify(self.workspace.label)
127
+
128
+    @property
129
+    def sidebar_entries(self) -> typing.List[WorkspaceMenuEntry]:
130
+        """
131
+        get sidebar entries, those depends on activated apps.
132
+        """
133
+        # TODO - G.M - 22-05-2018 - Rework on this in
134
+        # order to not use hardcoded list
135
+        # list should be able to change (depending on activated/disabled
136
+        # apps)
137
+        return default_workspace_menu_entry(self.workspace)
138
+
139
+
140
+class UserRoleWorkspaceInContext(object):
141
+    """
142
+    Interface to get UserRoleInWorkspace data and related content
143
+
144
+    """
145
+    def __init__(
146
+            self,
147
+            user_role: UserRoleInWorkspace,
148
+            dbsession: Session,
149
+            config: CFG,
150
+    )-> None:
151
+        self.user_role = user_role
152
+        self.dbsession = dbsession
153
+        self.config = config
154
+
155
+    @property
156
+    def user_id(self) -> int:
157
+        """
158
+        User who has the role has this id
159
+        :return: user id as integer
160
+        """
161
+        return self.user_role.user_id
162
+
163
+    @property
164
+    def workspace_id(self) -> int:
165
+        """
166
+        This role apply only on the workspace with this workspace_id
167
+        :return: workspace id as integer
168
+        """
169
+        return self.user_role.workspace_id
170
+
171
+    # TODO - G.M - 23-05-2018 - Check the API spec for this this !
172
+
173
+    @property
174
+    def role_id(self) -> int:
175
+        """
176
+        role as int id, each value refer to a different role.
177
+        """
178
+        return self.user_role.role
179
+
180
+    @property
181
+    def role_slug(self) -> str:
182
+        """
183
+        simple name of the role of the user.
184
+        can be anything from UserRoleInWorkspace SLUG, like
185
+        'not_applicable', 'reader',
186
+        'contributor', 'content_manager', 'workspace_manager'
187
+        :return: user workspace role as slug.
188
+        """
189
+        return UserRoleInWorkspace.SLUG[self.user_role.role]
190
+
191
+    @property
192
+    def user(self) -> UserInContext:
193
+        """
194
+        User who has this role, with context data
195
+        :return: UserInContext object
196
+        """
197
+        return UserInContext(
198
+            self.user_role.user,
199
+            self.dbsession,
200
+            self.config
201
+        )
202
+
203
+    @property
204
+    def workspace(self) -> WorkspaceInContext:
205
+        """
206
+        Workspace related to this role, with his context data
207
+        :return: WorkspaceInContext object
208
+        """
209
+        return WorkspaceInContext(
210
+            self.user_role.workspace,
211
+            self.dbsession,
212
+            self.config
213
+        )

+ 33 - 10
tracim/models/data.py 查看文件

130
     CONTENT_MANAGER = 4
130
     CONTENT_MANAGER = 4
131
     WORKSPACE_MANAGER = 8
131
     WORKSPACE_MANAGER = 8
132
 
132
 
133
-    # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
133
+    SLUG = {
134
+        NOT_APPLICABLE: 'not-applicable',
135
+        READER: 'reader',
136
+        CONTRIBUTOR: 'contributor',
137
+        CONTENT_MANAGER: 'content-manager',
138
+        WORKSPACE_MANAGER: 'workspace-manager',
139
+    }
140
+
134
     LABEL = dict()
141
     LABEL = dict()
135
     LABEL[0] = l_('N/A')
142
     LABEL[0] = l_('N/A')
136
     LABEL[1] = l_('Reader')
143
     LABEL[1] = l_('Reader')
137
     LABEL[2] = l_('Contributor')
144
     LABEL[2] = l_('Contributor')
138
     LABEL[4] = l_('Content Manager')
145
     LABEL[4] = l_('Content Manager')
139
     LABEL[8] = l_('Workspace Manager')
146
     LABEL[8] = l_('Workspace Manager')
147
+    # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
140
     #
148
     #
141
     # STYLE = dict()
149
     # STYLE = dict()
142
     # STYLE[0] = ''
150
     # STYLE[0] = ''
154
     #
162
     #
155
     #
163
     #
156
     # @property
164
     # @property
157
-    # def icon(self):
165
+    # def fa_icon(self):
158
     #     return UserRoleInWorkspace.ICON[self.role]
166
     #     return UserRoleInWorkspace.ICON[self.role]
159
     #
167
     #
160
     # @property
168
     # @property
166
         return UserRoleInWorkspace.LABEL[self.role]
174
         return UserRoleInWorkspace.LABEL[self.role]
167
 
175
 
168
     @classmethod
176
     @classmethod
169
-    def get_all_role_values(self):
177
+    def get_all_role_values(cls) -> typing.List[int]:
178
+        """
179
+        Return all valid role value
180
+        """
170
         return [
181
         return [
171
             UserRoleInWorkspace.READER,
182
             UserRoleInWorkspace.READER,
172
             UserRoleInWorkspace.CONTRIBUTOR,
183
             UserRoleInWorkspace.CONTRIBUTOR,
174
             UserRoleInWorkspace.WORKSPACE_MANAGER
185
             UserRoleInWorkspace.WORKSPACE_MANAGER
175
         ]
186
         ]
176
 
187
 
188
+    @classmethod
189
+    def get_all_role_slug(cls) -> typing.List[str]:
190
+        """
191
+        Return all valid role slug
192
+        """
193
+        # INFO - G.M - 25-05-2018 - Be carefull, as long as this method
194
+        # and get_all_role_values are both used for API, this method should
195
+        # return item in the same order as get_all_role_values
196
+        return [cls.SLUG[value] for value in cls.get_all_role_values()]
197
+
198
+
177
 class RoleType(object):
199
 class RoleType(object):
178
     def __init__(self, role_id):
200
     def __init__(self, role_id):
179
         self.role_type_id = role_id
201
         self.role_type_id = role_id
180
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
202
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
181
-        # self.icon = UserRoleInWorkspace.ICON[role_id]
203
+        # self.fa_icon = UserRoleInWorkspace.ICON[role_id]
182
         # self.role_label = UserRoleInWorkspace.LABEL[role_id]
204
         # self.role_label = UserRoleInWorkspace.LABEL[role_id]
183
         # self.css_style = UserRoleInWorkspace.STYLE[role_id]
205
         # self.css_style = UserRoleInWorkspace.STYLE[role_id]
184
 
206
 
243
     def __init__(self, id):
265
     def __init__(self, id):
244
         assert id in ActionDescription.allowed_values()
266
         assert id in ActionDescription.allowed_values()
245
         self.id = id
267
         self.id = id
246
-        # FIXME - G.M - 17-04-2018 - Label and icon needed for webdav
268
+        # FIXME - G.M - 17-04-2018 - Label and fa_icon needed for webdav
247
         #  design template,
269
         #  design template,
248
         # find a way to not rely on this.
270
         # find a way to not rely on this.
249
         self.label = self.id
271
         self.label = self.id
250
-        self.icon = ActionDescription._ICONS[id]
272
+        self.fa_icon = ActionDescription._ICONS[id]
273
+        #self.icon = self.fa_icon
251
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
274
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
252
         # self.label = ActionDescription._LABELS[id]
275
         # self.label = ActionDescription._LABELS[id]
253
 
276
 
321
         self.id = id
344
         self.id = id
322
         self.label = self.id
345
         self.label = self.id
323
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
346
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
324
-        # self.icon = ContentStatus._ICONS[id]
347
+        # self.fa_icon = ContentStatus._ICONS[id]
325
         # self.css = ContentStatus._CSS[id]
348
         # self.css = ContentStatus._CSS[id]
326
         #
349
         #
327
         # if type==ContentType.Thread:
350
         # if type==ContentType.Thread:
498
     def __init__(self, type):
521
     def __init__(self, type):
499
         self.id = type
522
         self.id = type
500
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
523
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
501
-        # self.icon = ContentType._CSS_ICONS[type]
524
+        # self.fa_icon = ContentType._CSS_ICONS[type]
502
         # self.color = ContentType._CSS_COLORS[type]  # deprecated
525
         # self.color = ContentType._CSS_COLORS[type]  # deprecated
503
         # self.css = ContentType._CSS_COLORS[type]
526
         # self.css = ContentType._CSS_COLORS[type]
504
         # self.label = ContentType._LABEL[type]
527
         # self.label = ContentType._LABEL[type]
508
         return dict(id=self.type,
531
         return dict(id=self.type,
509
                     type=self.type,
532
                     type=self.type,
510
                     # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
533
                     # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
511
-                    # icon=self.icon,
534
+                    # fa_icon=self.fa_icon,
512
                     # color=self.color,
535
                     # color=self.color,
513
                     # label=self.label,
536
                     # label=self.label,
514
                     priority=self.priority)
537
                     priority=self.priority)
1435
         assert hasattr(type, 'id')
1458
         assert hasattr(type, 'id')
1436
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
1459
         # TODO - G.M - 10-04-2018 - [Cleanup] Drop this
1437
         # assert hasattr(type, 'css')
1460
         # assert hasattr(type, 'css')
1438
-        # assert hasattr(type, 'icon')
1461
+        # assert hasattr(type, 'fa_icon')
1439
         # assert hasattr(type, 'label')
1462
         # assert hasattr(type, 'label')
1440
 
1463
 
1441
     def created_as_delta(self, delta_from_datetime:datetime=None):
1464
     def created_as_delta(self, delta_from_datetime:datetime=None):

+ 71 - 0
tracim/models/workspace_menu_entries.py 查看文件

1
+# coding=utf-8
2
+import typing
3
+from copy import copy
4
+
5
+from tracim.models.applications import applications
6
+from tracim.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="",
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="",
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 - 0
tracim/tests/__init__.py 查看文件

162
         WorkspaceApi(
162
         WorkspaceApi(
163
             current_user=user,
163
             current_user=user,
164
             session=self.session,
164
             session=self.session,
165
+            config=self.app_config,
165
         ).create_workspace(name, save_now=True)
166
         ).create_workspace(name, save_now=True)
166
 
167
 
167
         eq_(
168
         eq_(

+ 2 - 0
tracim/tests/functional/test_mail_notification.py 查看文件

127
         wapi = WorkspaceApi(
127
         wapi = WorkspaceApi(
128
             current_user=current_user,
128
             current_user=current_user,
129
             session=self.session,
129
             session=self.session,
130
+            config=self.app_config,
130
         )
131
         )
131
         workspace = wapi.get_one_by_label('w1')
132
         workspace = wapi.get_one_by_label('w1')
132
         user = uapi.get_one_by_email('bob@fsf.local')
133
         user = uapi.get_one_by_email('bob@fsf.local')
218
         wapi = WorkspaceApi(
219
         wapi = WorkspaceApi(
219
             current_user=current_user,
220
             current_user=current_user,
220
             session=self.session,
221
             session=self.session,
222
+            config=self.app_config,
221
         )
223
         )
222
         workspace = wapi.get_one_by_label('w1')
224
         workspace = wapi.get_one_by_label('w1')
223
         user = uapi.get_one_by_email('bob@fsf.local')
225
         user = uapi.get_one_by_email('bob@fsf.local')

+ 77 - 0
tracim/tests/functional/test_system.py 查看文件

1
+# coding=utf-8
2
+from tracim.tests import FunctionalTest
3
+
4
+"""
5
+Tests for /api/v2/system subpath endpoints.
6
+"""
7
+
8
+class TestApplicationEndpoint(FunctionalTest):
9
+    """
10
+    Tests for /api/v2/system/applications
11
+    """
12
+
13
+    def test_api__get_applications__ok_200__nominal_case(self):
14
+        """
15
+        Get applications list with a registered user.
16
+        """
17
+        self.testapp.authorization = (
18
+            'Basic',
19
+            (
20
+                'admin@admin.admin',
21
+                'admin@admin.admin'
22
+            )
23
+        )
24
+        res = self.testapp.get('/api/v2/system/applications', status=200)
25
+        res = res.json_body
26
+        application = res[0]
27
+        assert application['label'] == "Text Documents"
28
+        assert application['slug'] == 'contents/htmlpage'
29
+        assert application['fa_icon'] == 'file-text-o'
30
+        assert application['hexcolor'] == '#3f52e3'
31
+        assert application['is_active'] is True
32
+        assert 'config' in application
33
+        application = res[1]
34
+        assert application['label'] == "Markdown Plus Documents"
35
+        assert application['slug'] == 'contents/markdownpluspage'
36
+        assert application['fa_icon'] == 'file-code'
37
+        assert application['hexcolor'] == '#f12d2d'
38
+        assert application['is_active'] is True
39
+        assert 'config' in application
40
+        application = res[2]
41
+        assert application['label'] == "Files"
42
+        assert application['slug'] == 'contents/files'
43
+        assert application['fa_icon'] == 'paperclip'
44
+        assert application['hexcolor'] == '#FF9900'
45
+        assert application['is_active'] is True
46
+        assert 'config' in application
47
+        application = res[3]
48
+        assert application['label'] == "Threads"
49
+        assert application['slug'] == 'contents/threads'
50
+        assert application['fa_icon'] == 'comments-o'
51
+        assert application['hexcolor'] == '#ad4cf9'
52
+        assert application['is_active'] is True
53
+        assert 'config' in application
54
+        application = res[4]
55
+        assert application['label'] == "Calendar"
56
+        assert application['slug'] == 'calendar'
57
+        assert application['fa_icon'] == 'calendar-alt'
58
+        assert application['hexcolor'] == '#757575'
59
+        assert application['is_active'] is True
60
+        assert 'config' in application
61
+
62
+    def test_api__get_workspace__err_401__unregistered_user(self):
63
+        """
64
+        Get applications list with an unregistered user (bad auth)
65
+        """
66
+        self.testapp.authorization = (
67
+            'Basic',
68
+            (
69
+                'john@doe.doe',
70
+                'lapin'
71
+            )
72
+        )
73
+        res = self.testapp.get('/api/v2/system/applications', status=401)
74
+        assert isinstance(res.json, dict)
75
+        assert 'code' in res.json.keys()
76
+        assert 'message' in res.json.keys()
77
+        assert 'details' in res.json.keys()

+ 137 - 0
tracim/tests/functional/test_user.py 查看文件

1
+# -*- coding: utf-8 -*-
2
+"""
3
+Tests for /api/v2/users subpath endpoints.
4
+"""
5
+from tracim.tests import FunctionalTest
6
+from tracim.fixtures.content import Content as ContentFixtures
7
+from tracim.fixtures.users_and_groups import Base as BaseFixture
8
+
9
+
10
+class TestUserWorkspaceEndpoint(FunctionalTest):
11
+    # -*- coding: utf-8 -*-
12
+    """
13
+    Tests for /api/v2/users/{user_id}/workspaces
14
+    """
15
+    fixtures = [BaseFixture, ContentFixtures]
16
+
17
+    def test_api__get_user_workspaces__ok_200__nominal_case(self):
18
+        """
19
+        Check obtain all workspaces reachables for user with user auth.
20
+        """
21
+        self.testapp.authorization = (
22
+            'Basic',
23
+            (
24
+                'admin@admin.admin',
25
+                'admin@admin.admin'
26
+            )
27
+        )
28
+        res = self.testapp.get('/api/v2/users/1/workspaces', status=200)
29
+        res = res.json_body
30
+        workspace = res[0]
31
+        assert workspace['id'] == 1
32
+        assert workspace['label'] == 'w1'
33
+        assert len(workspace['sidebar_entries']) == 7
34
+
35
+        sidebar_entry = workspace['sidebar_entries'][0]
36
+        assert sidebar_entry['slug'] == 'dashboard'
37
+        assert sidebar_entry['label'] == 'Dashboard'
38
+        assert sidebar_entry['route'] == '/#/workspaces/1/dashboard'  # nopep8
39
+        assert sidebar_entry['hexcolor'] == "#252525"
40
+        assert sidebar_entry['fa_icon'] == ""
41
+
42
+        sidebar_entry = workspace['sidebar_entries'][1]
43
+        assert sidebar_entry['slug'] == 'contents/all'
44
+        assert sidebar_entry['label'] == 'All Contents'
45
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents"  # nopep8
46
+        assert sidebar_entry['hexcolor'] == "#fdfdfd"
47
+        assert sidebar_entry['fa_icon'] == ""
48
+
49
+        sidebar_entry = workspace['sidebar_entries'][2]
50
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
51
+        assert sidebar_entry['label'] == 'Text Documents'
52
+        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=htmlpage'  # nopep8
53
+        assert sidebar_entry['hexcolor'] == "#3f52e3"
54
+        assert sidebar_entry['fa_icon'] == "file-text-o"
55
+
56
+        sidebar_entry = workspace['sidebar_entries'][3]
57
+        assert sidebar_entry['slug'] == 'contents/markdownpluspage'
58
+        assert sidebar_entry['label'] == 'Markdown Plus Documents'
59
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=markdownpluspage"    # nopep8
60
+        assert sidebar_entry['hexcolor'] == "#f12d2d"
61
+        assert sidebar_entry['fa_icon'] == "file-code"
62
+
63
+        sidebar_entry = workspace['sidebar_entries'][4]
64
+        assert sidebar_entry['slug'] == 'contents/files'
65
+        assert sidebar_entry['label'] == 'Files'
66
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=file"  # nopep8
67
+        assert sidebar_entry['hexcolor'] == "#FF9900"
68
+        assert sidebar_entry['fa_icon'] == "paperclip"
69
+
70
+        sidebar_entry = workspace['sidebar_entries'][5]
71
+        assert sidebar_entry['slug'] == 'contents/threads'
72
+        assert sidebar_entry['label'] == 'Threads'
73
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=thread"  # nopep8
74
+        assert sidebar_entry['hexcolor'] == "#ad4cf9"
75
+        assert sidebar_entry['fa_icon'] == "comments-o"
76
+
77
+        sidebar_entry = workspace['sidebar_entries'][6]
78
+        assert sidebar_entry['slug'] == 'calendar'
79
+        assert sidebar_entry['label'] == 'Calendar'
80
+        assert sidebar_entry['route'] == "/#/workspaces/1/calendar"  # nopep8
81
+        assert sidebar_entry['hexcolor'] == "#757575"
82
+        assert sidebar_entry['fa_icon'] == "calendar-alt"
83
+
84
+    def test_api__get_user_workspaces__err_403__unallowed_user(self):
85
+        """
86
+        Check obtain all workspaces reachables for one user
87
+        with another non-admin user auth.
88
+        """
89
+        self.testapp.authorization = (
90
+            'Basic',
91
+            (
92
+                'lawrence-not-real-email@fsf.local',
93
+                'foobarbaz'
94
+            )
95
+        )
96
+        res = self.testapp.get('/api/v2/users/1/workspaces', status=403)
97
+        assert isinstance(res.json, dict)
98
+        assert 'code' in res.json.keys()
99
+        assert 'message' in res.json.keys()
100
+        assert 'details' in res.json.keys()
101
+
102
+    def test_api__get_user_workspaces__err_401__unregistered_user(self):
103
+        """
104
+        Check obtain all workspaces reachables for one user
105
+        without correct user auth (user unregistered).
106
+        """
107
+        self.testapp.authorization = (
108
+            'Basic',
109
+            (
110
+                'john@doe.doe',
111
+                'lapin'
112
+            )
113
+        )
114
+        res = self.testapp.get('/api/v2/users/1/workspaces', status=401)
115
+        assert isinstance(res.json, dict)
116
+        assert 'code' in res.json.keys()
117
+        assert 'message' in res.json.keys()
118
+        assert 'details' in res.json.keys()
119
+
120
+    def test_api__get_user_workspaces__err_404__user_does_not_exist(self):
121
+        """
122
+        Check obtain all workspaces reachables for one user who does
123
+        not exist
124
+        with a correct user auth.
125
+        """
126
+        self.testapp.authorization = (
127
+            'Basic',
128
+            (
129
+                'admin@admin.admin',
130
+                'admin@admin.admin'
131
+            )
132
+        )
133
+        res = self.testapp.get('/api/v2/users/5/workspaces', status=404)
134
+        assert isinstance(res.json, dict)
135
+        assert 'code' in res.json.keys()
136
+        assert 'message' in res.json.keys()
137
+        assert 'details' in res.json.keys()

+ 218 - 0
tracim/tests/functional/test_workspaces.py 查看文件

1
+# -*- coding: utf-8 -*-
2
+"""
3
+Tests for /api/v2/workspaces subpath endpoints.
4
+"""
5
+from tracim.tests import FunctionalTest
6
+from tracim.fixtures.content import Content as ContentFixtures
7
+from tracim.fixtures.users_and_groups import Base as BaseFixture
8
+
9
+
10
+class TestWorkspaceEndpoint(FunctionalTest):
11
+    """
12
+    Tests for /api/v2/workspaces/{workspace_id} endpoint
13
+    """
14
+
15
+    fixtures = [BaseFixture, ContentFixtures]
16
+
17
+    def test_api__get_workspace__ok_200__nominal_case(self) -> None:
18
+        """
19
+        Check obtain workspace reachable for user.
20
+        """
21
+        self.testapp.authorization = (
22
+            'Basic',
23
+            (
24
+                'admin@admin.admin',
25
+                'admin@admin.admin'
26
+            )
27
+        )
28
+        res = self.testapp.get('/api/v2/workspaces/1', status=200)
29
+        workspace = res.json_body
30
+        assert workspace['id'] == 1
31
+        assert workspace['slug'] == 'w1'
32
+        assert workspace['label'] == 'w1'
33
+        assert workspace['description'] == 'This is a workspace'
34
+        assert len(workspace['sidebar_entries']) == 7
35
+
36
+        sidebar_entry = workspace['sidebar_entries'][0]
37
+        assert sidebar_entry['slug'] == 'dashboard'
38
+        assert sidebar_entry['label'] == 'Dashboard'
39
+        assert sidebar_entry['route'] == '/#/workspaces/1/dashboard'  # nopep8
40
+        assert sidebar_entry['hexcolor'] == "#252525"
41
+        assert sidebar_entry['fa_icon'] == ""
42
+
43
+        sidebar_entry = workspace['sidebar_entries'][1]
44
+        assert sidebar_entry['slug'] == 'contents/all'
45
+        assert sidebar_entry['label'] == 'All Contents'
46
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents"  # nopep8
47
+        assert sidebar_entry['hexcolor'] == "#fdfdfd"
48
+        assert sidebar_entry['fa_icon'] == ""
49
+
50
+        sidebar_entry = workspace['sidebar_entries'][2]
51
+        assert sidebar_entry['slug'] == 'contents/htmlpage'
52
+        assert sidebar_entry['label'] == 'Text Documents'
53
+        assert sidebar_entry['route'] == '/#/workspaces/1/contents?type=htmlpage'  # nopep8
54
+        assert sidebar_entry['hexcolor'] == "#3f52e3"
55
+        assert sidebar_entry['fa_icon'] == "file-text-o"
56
+
57
+        sidebar_entry = workspace['sidebar_entries'][3]
58
+        assert sidebar_entry['slug'] == 'contents/markdownpluspage'
59
+        assert sidebar_entry['label'] == 'Markdown Plus Documents'
60
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=markdownpluspage"    # nopep8
61
+        assert sidebar_entry['hexcolor'] == "#f12d2d"
62
+        assert sidebar_entry['fa_icon'] == "file-code"
63
+
64
+        sidebar_entry = workspace['sidebar_entries'][4]
65
+        assert sidebar_entry['slug'] == 'contents/files'
66
+        assert sidebar_entry['label'] == 'Files'
67
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=file"  # nopep8
68
+        assert sidebar_entry['hexcolor'] == "#FF9900"
69
+        assert sidebar_entry['fa_icon'] == "paperclip"
70
+
71
+        sidebar_entry = workspace['sidebar_entries'][5]
72
+        assert sidebar_entry['slug'] == 'contents/threads'
73
+        assert sidebar_entry['label'] == 'Threads'
74
+        assert sidebar_entry['route'] == "/#/workspaces/1/contents?type=thread"  # nopep8
75
+        assert sidebar_entry['hexcolor'] == "#ad4cf9"
76
+        assert sidebar_entry['fa_icon'] == "comments-o"
77
+
78
+        sidebar_entry = workspace['sidebar_entries'][6]
79
+        assert sidebar_entry['slug'] == 'calendar'
80
+        assert sidebar_entry['label'] == 'Calendar'
81
+        assert sidebar_entry['route'] == "/#/workspaces/1/calendar"  # nopep8
82
+        assert sidebar_entry['hexcolor'] == "#757575"
83
+        assert sidebar_entry['fa_icon'] == "calendar-alt"
84
+
85
+    def test_api__get_workspace__err_403__unallowed_user(self) -> None:
86
+        """
87
+        Check obtain workspace unreachable for user
88
+        """
89
+        self.testapp.authorization = (
90
+            'Basic',
91
+            (
92
+                'lawrence-not-real-email@fsf.local',
93
+                'foobarbaz'
94
+            )
95
+        )
96
+        res = self.testapp.get('/api/v2/workspaces/1', status=403)
97
+        assert isinstance(res.json, dict)
98
+        assert 'code' in res.json.keys()
99
+        assert 'message' in res.json.keys()
100
+        assert 'details' in res.json.keys()
101
+
102
+    def test_api__get_workspace__err_401__unregistered_user(self) -> None:
103
+        """
104
+        Check obtain workspace without registered user.
105
+        """
106
+        self.testapp.authorization = (
107
+            'Basic',
108
+            (
109
+                'john@doe.doe',
110
+                'lapin'
111
+            )
112
+        )
113
+        res = self.testapp.get('/api/v2/workspaces/1', status=401)
114
+        assert isinstance(res.json, dict)
115
+        assert 'code' in res.json.keys()
116
+        assert 'message' in res.json.keys()
117
+        assert 'details' in res.json.keys()
118
+
119
+    def test_api__get_workspace__err_403__workspace_does_not_exist(self) -> None:  # nopep8
120
+        """
121
+        Check obtain workspace who does not exist with an existing user.
122
+        """
123
+        self.testapp.authorization = (
124
+            'Basic',
125
+            (
126
+                'admin@admin.admin',
127
+                'admin@admin.admin'
128
+            )
129
+        )
130
+        res = self.testapp.get('/api/v2/workspaces/5', status=403)
131
+        assert isinstance(res.json, dict)
132
+        assert 'code' in res.json.keys()
133
+        assert 'message' in res.json.keys()
134
+        assert 'details' in res.json.keys()
135
+
136
+
137
+class TestWorkspaceMembersEndpoint(FunctionalTest):
138
+    """
139
+    Tests for /api/v2/workspaces/{workspace_id}/members endpoint
140
+    """
141
+
142
+    fixtures = [BaseFixture, ContentFixtures]
143
+
144
+    def test_api__get_workspace_members__ok_200__nominal_case(self):
145
+        """
146
+        Check obtain workspace members list with a reachable workspace for user
147
+        """
148
+        self.testapp.authorization = (
149
+            'Basic',
150
+            (
151
+                'admin@admin.admin',
152
+                'admin@admin.admin'
153
+            )
154
+        )
155
+        res = self.testapp.get('/api/v2/workspaces/1/members', status=200).json_body   # nopep8
156
+        assert len(res) == 2
157
+        user_role = res[0]
158
+        assert user_role['role_slug'] == 'workspace-manager'
159
+        assert user_role['role_id'] == 8
160
+        assert user_role['user_id'] == 1
161
+        assert user_role['workspace_id'] == 1
162
+        assert user_role['user']['display_name'] == 'Global manager'
163
+        # TODO - G.M - 24-05-2018 - [Avatar] Replace
164
+        # by correct value when avatar feature will be enabled
165
+        assert user_role['user']['avatar_url'] is None
166
+
167
+    def test_api__get_workspace_members__err_403__unallowed_user(self):
168
+        """
169
+        Check obtain workspace members list with an unreachable workspace for
170
+        user
171
+        """
172
+        self.testapp.authorization = (
173
+            'Basic',
174
+            (
175
+                'lawrence-not-real-email@fsf.local',
176
+                'foobarbaz'
177
+            )
178
+        )
179
+        res = self.testapp.get('/api/v2/workspaces/3/members', status=403)
180
+        assert isinstance(res.json, dict)
181
+        assert 'code' in res.json.keys()
182
+        assert 'message' in res.json.keys()
183
+        assert 'details' in res.json.keys()
184
+
185
+    def test_api__get_workspace_members__err_401__unregistered_user(self):
186
+        """
187
+        Check obtain workspace members list with an unregistered user
188
+        """
189
+        self.testapp.authorization = (
190
+            'Basic',
191
+            (
192
+                'john@doe.doe',
193
+                'lapin'
194
+            )
195
+        )
196
+        res = self.testapp.get('/api/v2/workspaces/1/members', status=401)
197
+        assert isinstance(res.json, dict)
198
+        assert 'code' in res.json.keys()
199
+        assert 'message' in res.json.keys()
200
+        assert 'details' in res.json.keys()
201
+
202
+    def test_api__get_workspace_members__err_403__workspace_does_not_exist(self):  # nopep8
203
+        """
204
+        Check obtain workspace members list with an existing user but
205
+        an unexisting workspace
206
+        """
207
+        self.testapp.authorization = (
208
+            'Basic',
209
+            (
210
+                'admin@admin.admin',
211
+                'admin@admin.admin'
212
+            )
213
+        )
214
+        res = self.testapp.get('/api/v2/workspaces/5/members', status=403)
215
+        assert isinstance(res.json, dict)
216
+        assert 'code' in res.json.keys()
217
+        assert 'message' in res.json.keys()
218
+        assert 'details' in res.json.keys()

+ 223 - 61
tracim/tests/library/test_content_api.py 查看文件

107
             config=self.app_config,
107
             config=self.app_config,
108
             current_user=None,
108
             current_user=None,
109
         )
109
         )
110
-        group_api = GroupApi(current_user=None,session=self.session)
110
+        group_api = GroupApi(
111
+            current_user=None,
112
+            session=self.session,
113
+            config=self.app_config,
114
+        )
111
         groups = [group_api.get_one(Group.TIM_USER),
115
         groups = [group_api.get_one(Group.TIM_USER),
112
                   group_api.get_one(Group.TIM_MANAGER),
116
                   group_api.get_one(Group.TIM_MANAGER),
113
                   group_api.get_one(Group.TIM_ADMIN)]
117
                   group_api.get_one(Group.TIM_ADMIN)]
116
                                         groups=groups, save_now=True)
120
                                         groups=groups, save_now=True)
117
         workspace = WorkspaceApi(
121
         workspace = WorkspaceApi(
118
             current_user=user,
122
             current_user=user,
119
-            session=self.session
123
+            session=self.session,
124
+            config=self.app_config,
120
         ).create_workspace('test workspace', save_now=True)
125
         ).create_workspace('test workspace', save_now=True)
121
         api = ContentApi(
126
         api = ContentApi(
122
             current_user=user,
127
             current_user=user,
133
 
138
 
134
         # Refresh instances after commit
139
         # Refresh instances after commit
135
         user = uapi.get_one(uid)
140
         user = uapi.get_one(uid)
136
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
141
+        workspace_api = WorkspaceApi(
142
+            current_user=user,
143
+            session=self.session,
144
+            config=self.app_config
145
+        )
137
         workspace = workspace_api.get_one(wid)
146
         workspace = workspace_api.get_one(wid)
138
         api = ContentApi(
147
         api = ContentApi(
139
             current_user=user,
148
             current_user=user,
154
 
163
 
155
         # Refresh instances after commit
164
         # Refresh instances after commit
156
         user = uapi.get_one(uid)
165
         user = uapi.get_one(uid)
157
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
166
+        workspace_api = WorkspaceApi(
167
+            current_user=user,
168
+            session=self.session,
169
+            config=self.app_config
170
+        )
158
         workspace = workspace_api.get_one(wid)
171
         workspace = workspace_api.get_one(wid)
159
         api = ContentApi(
172
         api = ContentApi(
160
             current_user=user, 
173
             current_user=user, 
168
         # Test that the item is still available if "show deleted" is activated
181
         # Test that the item is still available if "show deleted" is activated
169
         # Refresh instances after commit
182
         # Refresh instances after commit
170
         user = uapi.get_one(uid)
183
         user = uapi.get_one(uid)
171
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
184
+        workspace_api = WorkspaceApi(
185
+            current_user=user,
186
+            session=self.session,
187
+            config=self.app_config,
188
+        )
172
         api = ContentApi(
189
         api = ContentApi(
173
             current_user=user,
190
             current_user=user,
174
             session=self.session,
191
             session=self.session,
184
             config=self.app_config,
201
             config=self.app_config,
185
             current_user=None,
202
             current_user=None,
186
         )
203
         )
187
-        group_api = GroupApi(current_user=None, session=self.session)
204
+        group_api = GroupApi(
205
+            current_user=None,
206
+            session=self.session,
207
+            config=self.app_config,
208
+        )
188
         groups = [group_api.get_one(Group.TIM_USER),
209
         groups = [group_api.get_one(Group.TIM_USER),
189
                   group_api.get_one(Group.TIM_MANAGER),
210
                   group_api.get_one(Group.TIM_MANAGER),
190
                   group_api.get_one(Group.TIM_ADMIN)]
211
                   group_api.get_one(Group.TIM_ADMIN)]
191
 
212
 
192
-        user = uapi.create_minimal_user(email='this.is@user',
193
-                                        groups=groups, save_now=True)
194
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
213
+        user = uapi.create_minimal_user(
214
+            email='this.is@user',
215
+            groups=groups,
216
+            save_now=True
217
+        )
218
+        workspace_api = WorkspaceApi(
219
+            current_user=user,
220
+            session=self.session,
221
+            config=self.app_config
222
+        )
223
+
195
         workspace = workspace_api.create_workspace(
224
         workspace = workspace_api.create_workspace(
196
             'test workspace',
225
             'test workspace',
197
             save_now=True
226
             save_now=True
210
         transaction.commit()
239
         transaction.commit()
211
         # Refresh instances after commit
240
         # Refresh instances after commit
212
         user = uapi.get_one(uid)
241
         user = uapi.get_one(uid)
213
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
242
+        workspace_api = WorkspaceApi(
243
+            current_user=user,
244
+            session=self.session,
245
+            config=self.app_config,
246
+        )
214
         api = ContentApi(
247
         api = ContentApi(
215
             session=self.session,
248
             session=self.session,
216
             current_user=user,
249
             current_user=user,
231
 
264
 
232
         # Refresh instances after commit
265
         # Refresh instances after commit
233
         user = uapi.get_one(uid)
266
         user = uapi.get_one(uid)
234
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
267
+        workspace_api = WorkspaceApi(
268
+            current_user=user,
269
+            session=self.session,
270
+            config=self.app_config,
271
+        )
235
         workspace = workspace_api.get_one(wid)
272
         workspace = workspace_api.get_one(wid)
236
         api = ContentApi(
273
         api = ContentApi(
237
             current_user=user, 
274
             current_user=user, 
245
 
282
 
246
         # Refresh instances after commit
283
         # Refresh instances after commit
247
         user = uapi.get_one(uid)
284
         user = uapi.get_one(uid)
248
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
285
+        workspace_api = WorkspaceApi(
286
+            current_user=user,
287
+            session=self.session,
288
+            config=self.app_config,
289
+        )
249
         workspace = workspace_api.get_one(wid)
290
         workspace = workspace_api.get_one(wid)
250
         api = ContentApi(
291
         api = ContentApi(
251
             current_user=user,
292
             current_user=user,
269
             config=self.app_config,
310
             config=self.app_config,
270
             current_user=None,
311
             current_user=None,
271
         )
312
         )
272
-        group_api = GroupApi(current_user=None, session=self.session)
313
+        group_api = GroupApi(
314
+            current_user=None,
315
+            session=self.session,
316
+            config=self.app_config,
317
+        )
273
         groups = [group_api.get_one(Group.TIM_USER),
318
         groups = [group_api.get_one(Group.TIM_USER),
274
                   group_api.get_one(Group.TIM_MANAGER),
319
                   group_api.get_one(Group.TIM_MANAGER),
275
                   group_api.get_one(Group.TIM_ADMIN)]
320
                   group_api.get_one(Group.TIM_ADMIN)]
281
         )
326
         )
282
         workspace = WorkspaceApi(
327
         workspace = WorkspaceApi(
283
             current_user=user,
328
             current_user=user,
284
-            session=self.session
329
+            session=self.session,
330
+            config=self.app_config,
285
         ).create_workspace(
331
         ).create_workspace(
286
             'test workspace',
332
             'test workspace',
287
             save_now=True
333
             save_now=True
301
 
347
 
302
         # Refresh instances after commit
348
         # Refresh instances after commit
303
         user = uapi.get_one(uid)
349
         user = uapi.get_one(uid)
304
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
350
+        workspace_api = WorkspaceApi(
351
+            current_user=user,
352
+            session=self.session,
353
+            config=self.app_config,
354
+        )
305
         workspace = workspace_api.get_one(wid)
355
         workspace = workspace_api.get_one(wid)
306
         api = ContentApi(
356
         api = ContentApi(
307
             current_user=user, 
357
             current_user=user, 
326
             config=self.app_config,
376
             config=self.app_config,
327
             current_user=None,
377
             current_user=None,
328
         )
378
         )
329
-        group_api = GroupApi(current_user=None, session=self.session)
379
+        group_api = GroupApi(
380
+            current_user=None,
381
+            session=self.session,
382
+            config=self.app_config
383
+        )
330
         groups = [group_api.get_one(Group.TIM_USER),
384
         groups = [group_api.get_one(Group.TIM_USER),
331
                   group_api.get_one(Group.TIM_MANAGER),
385
                   group_api.get_one(Group.TIM_MANAGER),
332
                   group_api.get_one(Group.TIM_ADMIN)]
386
                   group_api.get_one(Group.TIM_ADMIN)]
335
                                         groups=groups, save_now=True)
389
                                         groups=groups, save_now=True)
336
         workspace = WorkspaceApi(
390
         workspace = WorkspaceApi(
337
             current_user=user,
391
             current_user=user,
338
-            session=self.session
392
+            session=self.session,
393
+            config=self.app_config
339
         ).create_workspace('test workspace', save_now=True)
394
         ).create_workspace('test workspace', save_now=True)
340
         api = ContentApi(
395
         api = ContentApi(
341
             current_user=user, 
396
             current_user=user, 
371
 
426
 
372
         # Refresh instances after commit
427
         # Refresh instances after commit
373
         user = uapi.get_one(uid)
428
         user = uapi.get_one(uid)
374
-        workspace_api = WorkspaceApi(current_user=user, session=self.session)
429
+        workspace_api = WorkspaceApi(
430
+            current_user=user,
431
+            session=self.session,
432
+            config=self.app_config,
433
+        )
375
         workspace = workspace_api.get_one(wid)
434
         workspace = workspace_api.get_one(wid)
376
         api = ContentApi(
435
         api = ContentApi(
377
             current_user=user,
436
             current_user=user,
394
         )
453
         )
395
         group_api = GroupApi(
454
         group_api = GroupApi(
396
             current_user=None,
455
             current_user=None,
397
-            session=self.session
456
+            session=self.session,
457
+            config=self.app_config,
398
         )
458
         )
399
         groups = [group_api.get_one(Group.TIM_USER),
459
         groups = [group_api.get_one(Group.TIM_USER),
400
                   group_api.get_one(Group.TIM_MANAGER),
460
                   group_api.get_one(Group.TIM_MANAGER),
405
 
465
 
406
         workspace = WorkspaceApi(
466
         workspace = WorkspaceApi(
407
             current_user=user,
467
             current_user=user,
408
-            session=self.session
468
+            session=self.session,
469
+            config=self.app_config,
409
         ).create_workspace(
470
         ).create_workspace(
410
             'test workspace',
471
             'test workspace',
411
             save_now=True
472
             save_now=True
432
         )
493
         )
433
         group_api = GroupApi(
494
         group_api = GroupApi(
434
             current_user=None,
495
             current_user=None,
435
-            session=self.session
496
+            session=self.session,
497
+            config=self.app_config,
436
         )
498
         )
437
         groups = [group_api.get_one(Group.TIM_USER),
499
         groups = [group_api.get_one(Group.TIM_USER),
438
                   group_api.get_one(Group.TIM_MANAGER),
500
                   group_api.get_one(Group.TIM_MANAGER),
443
 
505
 
444
         workspace = WorkspaceApi(
506
         workspace = WorkspaceApi(
445
             current_user=user,
507
             current_user=user,
446
-            session=self.session
508
+            session=self.session,
509
+            config=self.app_config,
447
         ).create_workspace(
510
         ).create_workspace(
448
             'test workspace',
511
             'test workspace',
449
             save_now=True
512
             save_now=True
474
         )
537
         )
475
         group_api = GroupApi(
538
         group_api = GroupApi(
476
             current_user=None,
539
             current_user=None,
477
-            session=self.session
540
+            session=self.session,
541
+            config=self.config,
478
         )
542
         )
479
         groups = [group_api.get_one(Group.TIM_USER),
543
         groups = [group_api.get_one(Group.TIM_USER),
480
                   group_api.get_one(Group.TIM_MANAGER),
544
                   group_api.get_one(Group.TIM_MANAGER),
485
 
549
 
486
         workspace = WorkspaceApi(
550
         workspace = WorkspaceApi(
487
             current_user=user,
551
             current_user=user,
488
-            session=self.session
552
+            session=self.session,
553
+            config=self.app_config,
489
         ).create_workspace(
554
         ).create_workspace(
490
             'test workspace',
555
             'test workspace',
491
             save_now=True
556
             save_now=True
516
         )
581
         )
517
         group_api = GroupApi(
582
         group_api = GroupApi(
518
             current_user=None,
583
             current_user=None,
519
-            session=self.session
584
+            session=self.session,
585
+            config=self.app_config
520
         )
586
         )
521
         groups = [group_api.get_one(Group.TIM_USER),
587
         groups = [group_api.get_one(Group.TIM_USER),
522
                   group_api.get_one(Group.TIM_MANAGER),
588
                   group_api.get_one(Group.TIM_MANAGER),
534
         )
600
         )
535
         workspace = WorkspaceApi(
601
         workspace = WorkspaceApi(
536
             current_user=user,
602
             current_user=user,
537
-            session=self.session
603
+            session=self.session,
604
+            config=self.app_config,
538
         ).create_workspace(
605
         ).create_workspace(
539
             'test workspace',
606
             'test workspace',
540
             save_now=True
607
             save_now=True
541
         )
608
         )
542
-        RoleApi(current_user=user, session=self.session).create_one(
609
+        RoleApi(
610
+            current_user=user,
611
+            session=self.session,
612
+            config=self.app_config,
613
+        ).create_one(
543
             user2,
614
             user2,
544
             workspace,
615
             workspace,
545
             UserRoleInWorkspace.WORKSPACE_MANAGER,
616
             UserRoleInWorkspace.WORKSPACE_MANAGER,
581
         workspace2 = WorkspaceApi(
652
         workspace2 = WorkspaceApi(
582
             current_user=user2,
653
             current_user=user2,
583
             session=self.session,
654
             session=self.session,
655
+            config=self.app_config,
584
         ).create_workspace(
656
         ).create_workspace(
585
             'test workspace2',
657
             'test workspace2',
586
             save_now=True
658
             save_now=True
628
         )
700
         )
629
         group_api = GroupApi(
701
         group_api = GroupApi(
630
             current_user=None,
702
             current_user=None,
631
-            session=self.session
703
+            session=self.session,
704
+            config=self.app_config,
632
         )
705
         )
633
         groups = [group_api.get_one(Group.TIM_USER),
706
         groups = [group_api.get_one(Group.TIM_USER),
634
                   group_api.get_one(Group.TIM_MANAGER),
707
                   group_api.get_one(Group.TIM_MANAGER),
646
         )
719
         )
647
         workspace = WorkspaceApi(
720
         workspace = WorkspaceApi(
648
             current_user=user,
721
             current_user=user,
649
-            session=self.session
722
+            session=self.session,
723
+            config=self.app_config,
650
         ).create_workspace(
724
         ).create_workspace(
651
             'test workspace',
725
             'test workspace',
652
             save_now=True
726
             save_now=True
653
         )
727
         )
654
-        RoleApi(current_user=user, session=self.session).create_one(
728
+        RoleApi(
729
+            current_user=user,
730
+            session=self.session,
731
+            config=self.app_config,
732
+        ).create_one(
655
             user2,
733
             user2,
656
             workspace,
734
             workspace,
657
             UserRoleInWorkspace.WORKSPACE_MANAGER,
735
             UserRoleInWorkspace.WORKSPACE_MANAGER,
692
         )
770
         )
693
         workspace2 = WorkspaceApi(
771
         workspace2 = WorkspaceApi(
694
             current_user=user2,
772
             current_user=user2,
695
-            session=self.session
773
+            session=self.session,
774
+            config=self.app_config,
696
         ).create_workspace(
775
         ).create_workspace(
697
             'test workspace2',
776
             'test workspace2',
698
             save_now=True
777
             save_now=True
738
         )
817
         )
739
         group_api = GroupApi(
818
         group_api = GroupApi(
740
             current_user=None,
819
             current_user=None,
741
-            session=self.session
820
+            session=self.session,
821
+            config=self.app_config,
742
         )
822
         )
743
         groups = [group_api.get_one(Group.TIM_USER),
823
         groups = [group_api.get_one(Group.TIM_USER),
744
                   group_api.get_one(Group.TIM_MANAGER),
824
                   group_api.get_one(Group.TIM_MANAGER),
756
         )
836
         )
757
         workspace = WorkspaceApi(
837
         workspace = WorkspaceApi(
758
             current_user=user,
838
             current_user=user,
759
-            session=self.session
839
+            session=self.session,
840
+            config=self.app_config,
760
         ).create_workspace(
841
         ).create_workspace(
761
             'test workspace',
842
             'test workspace',
762
             save_now=True
843
             save_now=True
763
         )
844
         )
764
-        RoleApi(current_user=user, session=self.session).create_one(
845
+        RoleApi(
846
+            current_user=user,
847
+            session=self.session,
848
+            config=self.app_config,
849
+        ).create_one(
765
             user2, workspace,
850
             user2, workspace,
766
             UserRoleInWorkspace.WORKSPACE_MANAGER,
851
             UserRoleInWorkspace.WORKSPACE_MANAGER,
767
             with_notif=False
852
             with_notif=False
837
         )
922
         )
838
         group_api = GroupApi(
923
         group_api = GroupApi(
839
             current_user=None,
924
             current_user=None,
840
-            session=self.session
925
+            session=self.session,
926
+            config=self.app_config,
841
         )
927
         )
842
         groups = [group_api.get_one(Group.TIM_USER),
928
         groups = [group_api.get_one(Group.TIM_USER),
843
                   group_api.get_one(Group.TIM_MANAGER),
929
                   group_api.get_one(Group.TIM_MANAGER),
851
         wapi = WorkspaceApi(
937
         wapi = WorkspaceApi(
852
             current_user=user_a,
938
             current_user=user_a,
853
             session=self.session,
939
             session=self.session,
940
+            config=self.app_config,
854
         )
941
         )
855
         workspace1 = wapi.create_workspace(
942
         workspace1 = wapi.create_workspace(
856
             'test workspace n°1',
943
             'test workspace n°1',
862
         role_api1 = RoleApi(
949
         role_api1 = RoleApi(
863
             current_user=user_a,
950
             current_user=user_a,
864
             session=self.session,
951
             session=self.session,
952
+            config=self.app_config,
865
         )
953
         )
866
         role_api1.create_one(
954
         role_api1.create_one(
867
             user_b,
955
             user_b,
873
         role_api2 = RoleApi(
961
         role_api2 = RoleApi(
874
             current_user=user_b,
962
             current_user=user_b,
875
             session=self.session,
963
             session=self.session,
964
+            config=self.app_config,
876
         )
965
         )
877
         role_api2.create_one(user_b, workspace2, UserRoleInWorkspace.READER,
966
         role_api2.create_one(user_b, workspace2, UserRoleInWorkspace.READER,
878
                              False)
967
                              False)
940
         )
1029
         )
941
         group_api = GroupApi(
1030
         group_api = GroupApi(
942
             current_user=None,
1031
             current_user=None,
943
-            session=self.session
1032
+            session=self.session,
1033
+            config = self.app_config,
944
         )
1034
         )
945
         groups = [group_api.get_one(Group.TIM_USER),
1035
         groups = [group_api.get_one(Group.TIM_USER),
946
                   group_api.get_one(Group.TIM_MANAGER),
1036
                   group_api.get_one(Group.TIM_MANAGER),
957
             save_now=True
1047
             save_now=True
958
         )
1048
         )
959
 
1049
 
960
-        wapi = WorkspaceApi(current_user=user_a, session=self.session)
1050
+        wapi = WorkspaceApi(
1051
+            current_user=user_a,
1052
+            session=self.session,
1053
+            config=self.app_config,
1054
+        )
961
         workspace_api = WorkspaceApi(
1055
         workspace_api = WorkspaceApi(
962
             current_user=user_a,
1056
             current_user=user_a,
963
-            session=self.session
1057
+            session=self.session,
1058
+            config=self.app_config,
964
         )
1059
         )
965
         workspace = wapi.create_workspace(
1060
         workspace = wapi.create_workspace(
966
             'test workspace',
1061
             'test workspace',
969
         role_api = RoleApi(
1064
         role_api = RoleApi(
970
             current_user=user_a,
1065
             current_user=user_a,
971
             session=self.session,
1066
             session=self.session,
1067
+            config=self.app_config,
972
         )
1068
         )
973
         role_api.create_one(
1069
         role_api.create_one(
974
             user_b,
1070
             user_b,
1004
             config=self.app_config,
1100
             config=self.app_config,
1005
             current_user=None,
1101
             current_user=None,
1006
         )
1102
         )
1007
-        group_api = GroupApi(current_user=None, session=self.session)
1103
+        group_api = GroupApi(
1104
+            current_user=None,
1105
+            session=self.session,
1106
+            config=self.app_config,
1107
+        )
1008
         groups = [group_api.get_one(Group.TIM_USER),
1108
         groups = [group_api.get_one(Group.TIM_USER),
1009
                   group_api.get_one(Group.TIM_MANAGER),
1109
                   group_api.get_one(Group.TIM_MANAGER),
1010
                   group_api.get_one(Group.TIM_ADMIN)]
1110
                   group_api.get_one(Group.TIM_ADMIN)]
1023
         wapi = WorkspaceApi(
1123
         wapi = WorkspaceApi(
1024
             current_user=user_a,
1124
             current_user=user_a,
1025
             session=self.session,
1125
             session=self.session,
1126
+            config=self.app_config,
1026
         )
1127
         )
1027
         workspace = wapi.create_workspace(
1128
         workspace = wapi.create_workspace(
1028
             'test workspace',
1129
             'test workspace',
1031
         role_api = RoleApi(
1132
         role_api = RoleApi(
1032
             current_user=user_a,
1133
             current_user=user_a,
1033
             session=self.session,
1134
             session=self.session,
1135
+            config=self.app_config,
1034
         )
1136
         )
1035
         role_api.create_one(
1137
         role_api.create_one(
1036
             user_b,
1138
             user_b,
1097
             config=self.app_config,
1199
             config=self.app_config,
1098
             current_user=None,
1200
             current_user=None,
1099
         )
1201
         )
1100
-        group_api = GroupApi(current_user=None, session=self.session)
1202
+        group_api = GroupApi(
1203
+            current_user=None,
1204
+            session=self.session,
1205
+            config=self.app_config,
1206
+        )
1101
         groups = [group_api.get_one(Group.TIM_USER),
1207
         groups = [group_api.get_one(Group.TIM_USER),
1102
                   group_api.get_one(Group.TIM_MANAGER),
1208
                   group_api.get_one(Group.TIM_MANAGER),
1103
                   group_api.get_one(Group.TIM_ADMIN)]
1209
                   group_api.get_one(Group.TIM_ADMIN)]
1108
             save_now=True
1214
             save_now=True
1109
         )
1215
         )
1110
 
1216
 
1111
-        workspace_api = WorkspaceApi(current_user=user1, session=self.session)
1217
+        workspace_api = WorkspaceApi(
1218
+            current_user=user1,
1219
+            session=self.session,
1220
+            config=self.app_config,
1221
+        )
1112
         workspace = workspace_api.create_workspace(
1222
         workspace = workspace_api.create_workspace(
1113
             'test workspace',
1223
             'test workspace',
1114
             save_now=True
1224
             save_now=True
1121
 
1231
 
1122
         RoleApi(
1232
         RoleApi(
1123
             current_user=user1,
1233
             current_user=user1,
1124
-            session=self.session
1234
+            session=self.session,
1235
+            config=self.app_config,
1125
         ).create_one(
1236
         ).create_one(
1126
             user2,
1237
             user2,
1127
             workspace,
1238
             workspace,
1152
         user1 = uapi.get_one(u1id)
1263
         user1 = uapi.get_one(u1id)
1153
         workspace = WorkspaceApi(
1264
         workspace = WorkspaceApi(
1154
             current_user=user1,
1265
             current_user=user1,
1155
-            session=self.session
1266
+            session=self.session,
1267
+            config=self.app_config,
1156
         ).get_one(wid)
1268
         ).get_one(wid)
1157
         api = ContentApi(
1269
         api = ContentApi(
1158
             current_user=user1,
1270
             current_user=user1,
1193
         workspace = WorkspaceApi(
1305
         workspace = WorkspaceApi(
1194
             current_user=user1,
1306
             current_user=user1,
1195
             session=self.session,
1307
             session=self.session,
1308
+            config=self.app_config,
1196
         ).get_one(wid)
1309
         ).get_one(wid)
1197
         api = ContentApi(
1310
         api = ContentApi(
1198
             current_user=user1,
1311
             current_user=user1,
1216
         )
1329
         )
1217
         group_api = GroupApi(
1330
         group_api = GroupApi(
1218
             current_user=None,
1331
             current_user=None,
1219
-            session=self.session
1332
+            session=self.session,
1333
+            config = self.app_config,
1220
         )
1334
         )
1221
         groups = [group_api.get_one(Group.TIM_USER),
1335
         groups = [group_api.get_one(Group.TIM_USER),
1222
                   group_api.get_one(Group.TIM_MANAGER),
1336
                   group_api.get_one(Group.TIM_MANAGER),
1231
         workspace = WorkspaceApi(
1345
         workspace = WorkspaceApi(
1232
             current_user=user1,
1346
             current_user=user1,
1233
             session=self.session,
1347
             session=self.session,
1348
+            config=self.app_config,
1234
         ).create_workspace(
1349
         ).create_workspace(
1235
             'test workspace',
1350
             'test workspace',
1236
             save_now=True
1351
             save_now=True
1241
 
1356
 
1242
         RoleApi(
1357
         RoleApi(
1243
             current_user=user1,
1358
             current_user=user1,
1244
-            session=self.session
1359
+            session=self.session,
1360
+            config=self.app_config,
1245
         ).create_one(
1361
         ).create_one(
1246
             user2,
1362
             user2,
1247
             workspace,
1363
             workspace,
1293
         )
1409
         )
1294
         group_api = GroupApi(
1410
         group_api = GroupApi(
1295
             current_user=None,
1411
             current_user=None,
1296
-            session=self.session
1412
+            session=self.session,
1413
+            config=self.app_config,
1297
         )
1414
         )
1298
         groups = [group_api.get_one(Group.TIM_USER),
1415
         groups = [group_api.get_one(Group.TIM_USER),
1299
                   group_api.get_one(Group.TIM_MANAGER),
1416
                   group_api.get_one(Group.TIM_MANAGER),
1305
             save_now=True
1422
             save_now=True
1306
         )
1423
         )
1307
 
1424
 
1308
-        workspace_api = WorkspaceApi(current_user=user1, session=self.session)
1425
+        workspace_api = WorkspaceApi(
1426
+            current_user=user1,
1427
+            session=self.session,
1428
+            config=self.app_config,
1429
+        )
1309
         workspace = workspace_api.create_workspace(
1430
         workspace = workspace_api.create_workspace(
1310
             'test workspace',
1431
             'test workspace',
1311
             save_now=True
1432
             save_now=True
1318
         RoleApi(
1439
         RoleApi(
1319
             current_user=user1,
1440
             current_user=user1,
1320
             session=self.session,
1441
             session=self.session,
1442
+            config=self.app_config,
1321
         ).create_one(
1443
         ).create_one(
1322
             user2,
1444
             user2,
1323
             workspace,
1445
             workspace,
1345
 
1467
 
1346
         # Refresh instances after commit
1468
         # Refresh instances after commit
1347
         user1 = uapi.get_one(u1id)
1469
         user1 = uapi.get_one(u1id)
1348
-        workspace_api2 = WorkspaceApi(current_user=user1, session=self.session)
1470
+        workspace_api2 = WorkspaceApi(
1471
+            current_user=user1,
1472
+            session=self.session,
1473
+            config=self.app_config,
1474
+        )
1349
         workspace = workspace_api2.get_one(wid)
1475
         workspace = workspace_api2.get_one(wid)
1350
         api = ContentApi(
1476
         api = ContentApi(
1351
             current_user=user1,
1477
             current_user=user1,
1387
         workspace = WorkspaceApi(
1513
         workspace = WorkspaceApi(
1388
             current_user=user1,
1514
             current_user=user1,
1389
             session=self.session,
1515
             session=self.session,
1516
+            config=self.app_config,
1390
         ).get_one(wid)
1517
         ).get_one(wid)
1391
 
1518
 
1392
         updated = api.get_one(pcid, ContentType.Any, workspace)
1519
         updated = api.get_one(pcid, ContentType.Any, workspace)
1407
         group_api = GroupApi(
1534
         group_api = GroupApi(
1408
             current_user=None,
1535
             current_user=None,
1409
             session=self.session,
1536
             session=self.session,
1537
+            config=self.app_config,
1410
         )
1538
         )
1411
         groups = [group_api.get_one(Group.TIM_USER),
1539
         groups = [group_api.get_one(Group.TIM_USER),
1412
                   group_api.get_one(Group.TIM_MANAGER),
1540
                   group_api.get_one(Group.TIM_MANAGER),
1418
             save_now=True,
1546
             save_now=True,
1419
         )
1547
         )
1420
 
1548
 
1421
-        workspace_api = WorkspaceApi(current_user=user1, session=self.session)
1549
+        workspace_api = WorkspaceApi(
1550
+            current_user=user1,
1551
+            session=self.session,
1552
+            config=self.app_config,
1553
+        )
1422
         workspace = workspace_api.create_workspace(
1554
         workspace = workspace_api.create_workspace(
1423
             'test workspace',
1555
             'test workspace',
1424
             save_now=True
1556
             save_now=True
1430
         RoleApi(
1562
         RoleApi(
1431
             current_user=user1,
1563
             current_user=user1,
1432
             session=self.session,
1564
             session=self.session,
1565
+            config=self.app_config,
1433
         ).create_one(
1566
         ).create_one(
1434
             user2,
1567
             user2,
1435
             workspace,
1568
             workspace,
1485
             config=self.app_config,
1618
             config=self.app_config,
1486
             current_user=None,
1619
             current_user=None,
1487
         )
1620
         )
1488
-        group_api = GroupApi(current_user=None, session=self.session)
1621
+        group_api = GroupApi(
1622
+            current_user=None,
1623
+            session=self.session,
1624
+            config=self.app_config,
1625
+        )
1489
         groups = [group_api.get_one(Group.TIM_USER),
1626
         groups = [group_api.get_one(Group.TIM_USER),
1490
                   group_api.get_one(Group.TIM_MANAGER),
1627
                   group_api.get_one(Group.TIM_MANAGER),
1491
                   group_api.get_one(Group.TIM_ADMIN)]
1628
                   group_api.get_one(Group.TIM_ADMIN)]
1497
         )
1634
         )
1498
         u1id = user1.user_id
1635
         u1id = user1.user_id
1499
 
1636
 
1500
-        workspace_api = WorkspaceApi(current_user=user1, session=self.session)
1637
+        workspace_api = WorkspaceApi(
1638
+            current_user=user1,
1639
+            session=self.session,
1640
+            config=self.app_config,
1641
+        )
1501
         workspace = workspace_api.create_workspace(
1642
         workspace = workspace_api.create_workspace(
1502
             'test workspace',
1643
             'test workspace',
1503
             save_now=True
1644
             save_now=True
1509
 
1650
 
1510
         RoleApi(
1651
         RoleApi(
1511
             current_user=user1,
1652
             current_user=user1,
1512
-            session=self.session
1653
+            session=self.session,
1654
+            config=self.app_config,
1513
         ).create_one(
1655
         ).create_one(
1514
             user2,
1656
             user2,
1515
             workspace,
1657
             workspace,
1545
         ).get_one(u1id)
1687
         ).get_one(u1id)
1546
         workspace = WorkspaceApi(
1688
         workspace = WorkspaceApi(
1547
             current_user=user1,
1689
             current_user=user1,
1548
-            session=self.session
1690
+            session=self.session,
1691
+            config=self.app_config,
1549
         ).get_one(wid)
1692
         ).get_one(wid)
1550
 
1693
 
1551
         content = api.get_one(pcid, ContentType.Any, workspace)
1694
         content = api.get_one(pcid, ContentType.Any, workspace)
1583
         workspace = WorkspaceApi(
1726
         workspace = WorkspaceApi(
1584
             current_user=user1,
1727
             current_user=user1,
1585
             session=self.session,
1728
             session=self.session,
1729
+            config=self.app_config,
1586
         ).get_one(wid)
1730
         ).get_one(wid)
1587
         u2 = UserApi(
1731
         u2 = UserApi(
1588
             current_user=None,
1732
             current_user=None,
1632
         )
1776
         )
1633
         group_api = GroupApi(
1777
         group_api = GroupApi(
1634
             current_user=None,
1778
             current_user=None,
1635
-            session=self.session
1779
+            session=self.session,
1780
+            config=self.app_config,
1636
         )
1781
         )
1637
         groups = [group_api.get_one(Group.TIM_USER),
1782
         groups = [group_api.get_one(Group.TIM_USER),
1638
                   group_api.get_one(Group.TIM_MANAGER),
1783
                   group_api.get_one(Group.TIM_MANAGER),
1645
         )
1790
         )
1646
         u1id = user1.user_id
1791
         u1id = user1.user_id
1647
 
1792
 
1648
-        workspace_api = WorkspaceApi(current_user=user1, session=self.session)
1793
+        workspace_api = WorkspaceApi(
1794
+            current_user=user1,
1795
+            session=self.session,
1796
+            config=self.app_config,
1797
+        )
1649
         workspace = workspace_api.create_workspace(
1798
         workspace = workspace_api.create_workspace(
1650
             'test workspace',
1799
             'test workspace',
1651
             save_now=True
1800
             save_now=True
1657
 
1806
 
1658
         RoleApi(
1807
         RoleApi(
1659
             current_user=user1,
1808
             current_user=user1,
1660
-            session=self.session
1809
+            session=self.session,
1810
+            config=self.app_config,
1661
         ).create_one(
1811
         ).create_one(
1662
             user2,
1812
             user2,
1663
             workspace,
1813
             workspace,
1692
         workspace = WorkspaceApi(
1842
         workspace = WorkspaceApi(
1693
             current_user=user1,
1843
             current_user=user1,
1694
             session=self.session,
1844
             session=self.session,
1845
+            config=self.app_config,
1695
         ).get_one(wid)
1846
         ).get_one(wid)
1696
 
1847
 
1697
         content = api.get_one(pcid, ContentType.Any, workspace)
1848
         content = api.get_one(pcid, ContentType.Any, workspace)
1729
         workspace = WorkspaceApi(
1880
         workspace = WorkspaceApi(
1730
             current_user=user1,
1881
             current_user=user1,
1731
             session=self.session,
1882
             session=self.session,
1883
+            config=self.app_config,
1732
         ).get_one(wid)
1884
         ).get_one(wid)
1733
         # show archived is used at the top end of the test
1885
         # show archived is used at the top end of the test
1734
         api = ContentApi(
1886
         api = ContentApi(
1782
         group_api = GroupApi(
1934
         group_api = GroupApi(
1783
             current_user=None,
1935
             current_user=None,
1784
             session=self.session,
1936
             session=self.session,
1937
+            config=self.app_config,
1785
         )
1938
         )
1786
         groups = [group_api.get_one(Group.TIM_USER),
1939
         groups = [group_api.get_one(Group.TIM_USER),
1787
                   group_api.get_one(Group.TIM_MANAGER),
1940
                   group_api.get_one(Group.TIM_MANAGER),
1792
 
1945
 
1793
         workspace = WorkspaceApi(
1946
         workspace = WorkspaceApi(
1794
             current_user=user,
1947
             current_user=user,
1795
-            session=self.session
1948
+            session=self.session,
1949
+            config=self.app_config,
1796
         ).create_workspace(
1950
         ).create_workspace(
1797
             'test workspace',
1951
             'test workspace',
1798
             save_now=True
1952
             save_now=True
1802
             current_user=user, 
1956
             current_user=user, 
1803
             session=self.session,
1957
             session=self.session,
1804
             config=self.app_config,
1958
             config=self.app_config,
1805
-
1806
         )
1959
         )
1807
         a = api.create(ContentType.Folder, workspace, None,
1960
         a = api.create(ContentType.Folder, workspace, None,
1808
                        'this is randomized folder', True)
1961
                        'this is randomized folder', True)
1837
         group_api = GroupApi(
1990
         group_api = GroupApi(
1838
             current_user=None,
1991
             current_user=None,
1839
             session=self.session,
1992
             session=self.session,
1993
+            config=self.app_config,
1840
         )
1994
         )
1841
         groups = [group_api.get_one(Group.TIM_USER),
1995
         groups = [group_api.get_one(Group.TIM_USER),
1842
                   group_api.get_one(Group.TIM_MANAGER),
1996
                   group_api.get_one(Group.TIM_MANAGER),
1847
 
2001
 
1848
         workspace = WorkspaceApi(
2002
         workspace = WorkspaceApi(
1849
             current_user=user,
2003
             current_user=user,
1850
-            session=self.session
2004
+            session=self.session,
2005
+            config=self.app_config,
1851
         ).create_workspace(
2006
         ).create_workspace(
1852
             'test workspace',
2007
             'test workspace',
1853
             save_now=True,
2008
             save_now=True,
1888
             config=self.app_config,
2043
             config=self.app_config,
1889
             current_user=None,
2044
             current_user=None,
1890
         )
2045
         )
1891
-        group_api = GroupApi(current_user=None, session=self.session)
2046
+        group_api = GroupApi(
2047
+            current_user=None,
2048
+            session=self.session,
2049
+            config=self.app_config,
2050
+        )
1892
         groups = [group_api.get_one(Group.TIM_USER),
2051
         groups = [group_api.get_one(Group.TIM_USER),
1893
                   group_api.get_one(Group.TIM_MANAGER),
2052
                   group_api.get_one(Group.TIM_MANAGER),
1894
                   group_api.get_one(Group.TIM_ADMIN)]
2053
                   group_api.get_one(Group.TIM_ADMIN)]
1898
 
2057
 
1899
         workspace = WorkspaceApi(
2058
         workspace = WorkspaceApi(
1900
             current_user=user,
2059
             current_user=user,
1901
-            session=self.session
2060
+            session=self.session,
2061
+            config=self.app_config,
1902
         ).create_workspace('test workspace', save_now=True)
2062
         ).create_workspace('test workspace', save_now=True)
1903
 
2063
 
1904
         api = ContentApi(
2064
         api = ContentApi(
2032
         bob_workspace = WorkspaceApi(
2192
         bob_workspace = WorkspaceApi(
2033
             current_user=bob,
2193
             current_user=bob,
2034
             session=self.session,
2194
             session=self.session,
2195
+            config=self.app_config,
2035
         ).create_workspace(
2196
         ).create_workspace(
2036
             'bob_workspace',
2197
             'bob_workspace',
2037
             save_now=True,
2198
             save_now=True,
2039
         admin_workspace = WorkspaceApi(
2200
         admin_workspace = WorkspaceApi(
2040
             current_user=admin,
2201
             current_user=admin,
2041
             session=self.session,
2202
             session=self.session,
2203
+            config=self.app_config,
2042
         ).create_workspace(
2204
         ).create_workspace(
2043
             'admin_workspace',
2205
             'admin_workspace',
2044
             save_now=True,
2206
             save_now=True,

+ 4 - 4
tracim/tests/library/test_user_api.py 查看文件

4
 
4
 
5
 import transaction
5
 import transaction
6
 
6
 
7
-from tracim.exceptions import UserNotExist, AuthenticationFailed
7
+from tracim.exceptions import UserDoesNotExist, AuthenticationFailed
8
 from tracim.lib.core.user import UserApi
8
 from tracim.lib.core.user import UserApi
9
 from tracim.models import User
9
 from tracim.models import User
10
 from tracim.models.context_models import UserInContext
10
 from tracim.models.context_models import UserInContext
91
             session=self.session,
91
             session=self.session,
92
             config=self.config,
92
             config=self.config,
93
         )
93
         )
94
-        with pytest.raises(NoResultFound):
94
+        with pytest.raises(UserDoesNotExist):
95
             api.get_one_by_email('unknown')
95
             api.get_one_by_email('unknown')
96
 
96
 
97
     def test_unit__get_all__ok__nominal_case(self):
97
     def test_unit__get_all__ok__nominal_case(self):
158
             session=self.session,
158
             session=self.session,
159
             config=self.config,
159
             config=self.config,
160
         )
160
         )
161
-        with pytest.raises(UserNotExist):
161
+        with pytest.raises(UserDoesNotExist):
162
             api.get_current_user()
162
             api.get_current_user()
163
 
163
 
164
     def test_unit__authenticate_user___ok__nominal_case(self):
164
     def test_unit__authenticate_user___ok__nominal_case(self):
187
             config=self.config,
187
             config=self.config,
188
         )
188
         )
189
         with pytest.raises(AuthenticationFailed):
189
         with pytest.raises(AuthenticationFailed):
190
-            api.authenticate_user('unknown_user', 'wrong_password')
190
+            api.authenticate_user('admin@admin.admin', 'wrong_password')

+ 8 - 2
tracim/tests/library/test_workspace.py 查看文件

44
             .filter(User.email == 'admin@admin.admin').one()
44
             .filter(User.email == 'admin@admin.admin').one()
45
         wapi = WorkspaceApi(
45
         wapi = WorkspaceApi(
46
             session=self.session,
46
             session=self.session,
47
+            config=self.app_config,
47
             current_user=admin,
48
             current_user=admin,
48
         )
49
         )
49
         w = wapi.create_workspace(label='workspace w', save_now=True)
50
         w = wapi.create_workspace(label='workspace w', save_now=True)
57
         rapi = RoleApi(
58
         rapi = RoleApi(
58
             session=self.session,
59
             session=self.session,
59
             current_user=admin,
60
             current_user=admin,
61
+            config=self.app_config,
60
         )
62
         )
61
         r = rapi.create_one(u, w, UserRoleInWorkspace.READER, with_notif=True)
63
         r = rapi.create_one(u, w, UserRoleInWorkspace.READER, with_notif=True)
62
         eq_([r, ], wapi.get_notifiable_roles(workspace=w))
64
         eq_([r, ], wapi.get_notifiable_roles(workspace=w))
75
         wapi = WorkspaceApi(
77
         wapi = WorkspaceApi(
76
             session=self.session,
78
             session=self.session,
77
             current_user=admin,
79
             current_user=admin,
80
+            config=self.app_config,
78
         )
81
         )
79
         eq_([], wapi.get_all_manageable())
82
         eq_([], wapi.get_all_manageable())
80
         # Checks an admin gets all workspaces.
83
         # Checks an admin gets all workspaces.
87
         gapi = GroupApi(
90
         gapi = GroupApi(
88
             session=self.session,
91
             session=self.session,
89
             current_user=None,
92
             current_user=None,
93
+            config=self.app_config,
90
         )
94
         )
91
         u = uapi.create_minimal_user('u.s@e.r', [gapi.get_one(Group.TIM_USER)], True)
95
         u = uapi.create_minimal_user('u.s@e.r', [gapi.get_one(Group.TIM_USER)], True)
92
         wapi = WorkspaceApi(
96
         wapi = WorkspaceApi(
93
             session=self.session,
97
             session=self.session,
94
-            current_user=u
98
+            current_user=u,
99
+            config=self.app_config,
95
         )
100
         )
96
         rapi = RoleApi(
101
         rapi = RoleApi(
97
             session=self.session,
102
             session=self.session,
98
-            current_user=u
103
+            current_user=u,
104
+            config=self.app_config,
99
         )
105
         )
100
         rapi.create_one(u, w4, UserRoleInWorkspace.READER, False)
106
         rapi.create_one(u, w4, UserRoleInWorkspace.READER, False)
101
         rapi.create_one(u, w3, UserRoleInWorkspace.CONTRIBUTOR, False)
107
         rapi.create_one(u, w3, UserRoleInWorkspace.CONTRIBUTOR, False)

+ 0 - 0
tracim/views/core_api/__init__.py 查看文件


+ 62 - 3
tracim/views/core_api/schemas.py 查看文件

1
 # coding=utf-8
1
 # coding=utf-8
2
 import marshmallow
2
 import marshmallow
3
 from marshmallow import post_load
3
 from marshmallow import post_load
4
+from marshmallow.validate import OneOf
4
 
5
 
5
-from tracim.models.context_models import LoginCredentials, UserInContext
6
+from tracim.models.auth import Profile
7
+from tracim.models.context_models import LoginCredentials
8
+from tracim.models.data import UserRoleInWorkspace
6
 
9
 
7
 
10
 
8
 class ProfileSchema(marshmallow.Schema):
11
 class ProfileSchema(marshmallow.Schema):
9
-    id = marshmallow.fields.Int(dump_only=True)
10
-    slug = marshmallow.fields.String(attribute='name')
12
+    id = marshmallow.fields.Int(dump_only=True, validate=OneOf(Profile._IDS))
13
+    slug = marshmallow.fields.String(attribute='name', validate=OneOf(Profile._NAME))
11
 
14
 
12
 
15
 
13
 class UserSchema(marshmallow.Schema):
16
 class UserSchema(marshmallow.Schema):
32
     )
35
     )
33
 
36
 
34
 
37
 
38
+class UserIdPathSchema(marshmallow.Schema):
39
+    user_id = marshmallow.fields.Int()
40
+
41
+
42
+class WorkspaceIdPathSchema(marshmallow.Schema):
43
+    workspace_id = marshmallow.fields.Int()
44
+
45
+
35
 class BasicAuthSchema(marshmallow.Schema):
46
 class BasicAuthSchema(marshmallow.Schema):
36
 
47
 
37
     email = marshmallow.fields.Email(required=True)
48
     email = marshmallow.fields.Email(required=True)
48
 
59
 
49
 class NoContentSchema(marshmallow.Schema):
60
 class NoContentSchema(marshmallow.Schema):
50
     pass
61
     pass
62
+
63
+
64
+class WorkspaceMenuEntrySchema(marshmallow.Schema):
65
+    slug = marshmallow.fields.String()
66
+    label = marshmallow.fields.String()
67
+    route = marshmallow.fields.String()
68
+    hexcolor = marshmallow.fields.String()
69
+    fa_icon = marshmallow.fields.String()
70
+
71
+
72
+class WorkspaceDigestSchema(marshmallow.Schema):
73
+    id = marshmallow.fields.Int()
74
+    label = marshmallow.fields.String()
75
+    sidebar_entries = marshmallow.fields.Nested(
76
+        WorkspaceMenuEntrySchema,
77
+        many=True,
78
+    )
79
+
80
+
81
+class WorkspaceSchema(WorkspaceDigestSchema):
82
+    slug = marshmallow.fields.String()
83
+    description = marshmallow.fields.String()
84
+
85
+
86
+class WorkspaceMemberSchema(marshmallow.Schema):
87
+    role_id = marshmallow.fields.Int(validate=OneOf(UserRoleInWorkspace.get_all_role_values()))  # nopep8
88
+    role_slug = marshmallow.fields.String(validate=OneOf(UserRoleInWorkspace.get_all_role_slug()))  # nopep8
89
+    user_id = marshmallow.fields.Int()
90
+    workspace_id = marshmallow.fields.Int()
91
+    user = marshmallow.fields.Nested(
92
+        UserSchema(only=('display_name', 'avatar_url'))
93
+    )
94
+
95
+
96
+class ApplicationConfigSchema(marshmallow.Schema):
97
+    pass
98
+    #  TODO - G.M - 24-05-2018 - Set this
99
+
100
+
101
+class ApplicationSchema(marshmallow.Schema):
102
+    label = marshmallow.fields.String()
103
+    slug = marshmallow.fields.String()
104
+    fa_icon = marshmallow.fields.String()
105
+    hexcolor = marshmallow.fields.String()
106
+    is_active = marshmallow.fields.Boolean()
107
+    config = marshmallow.fields.Nested(
108
+        ApplicationConfigSchema,
109
+    )

+ 2 - 2
tracim/views/core_api/session_controller.py 查看文件

13
 from tracim.views.core_api.schemas import NoContentSchema
13
 from tracim.views.core_api.schemas import NoContentSchema
14
 from tracim.views.core_api.schemas import LoginOutputHeaders
14
 from tracim.views.core_api.schemas import LoginOutputHeaders
15
 from tracim.views.core_api.schemas import BasicAuthSchema
15
 from tracim.views.core_api.schemas import BasicAuthSchema
16
-from tracim.exceptions import NotAuthentificated
16
+from tracim.exceptions import NotAuthenticated
17
 from tracim.exceptions import AuthenticationFailed
17
 from tracim.exceptions import AuthenticationFailed
18
 
18
 
19
 
19
 
52
         return
52
         return
53
 
53
 
54
     @hapic.with_api_doc()
54
     @hapic.with_api_doc()
55
-    @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
55
+    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
56
     @hapic.output_body(UserSchema(),)
56
     @hapic.output_body(UserSchema(),)
57
     def whoami(self, context, request: TracimRequest, hapic_data=None):
57
     def whoami(self, context, request: TracimRequest, hapic_data=None):
58
         """
58
         """

+ 42 - 0
tracim/views/core_api/system_controller.py 查看文件

1
+# coding=utf-8
2
+from pyramid.config import Configurator
3
+
4
+from tracim.exceptions import NotAuthenticated, InsufficientUserProfile
5
+from tracim.lib.utils.authorization import require_profile
6
+from tracim.models import Group
7
+from tracim.models.applications import applications
8
+
9
+try:  # Python 3.5+
10
+    from http import HTTPStatus
11
+except ImportError:
12
+    from http import client as HTTPStatus
13
+
14
+from tracim import TracimRequest
15
+from tracim.extensions import hapic
16
+from tracim.views.controllers import Controller
17
+from tracim.views.core_api.schemas import ApplicationSchema
18
+
19
+
20
+class SystemController(Controller):
21
+
22
+    @hapic.with_api_doc()
23
+    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
24
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
25
+    @require_profile(Group.TIM_USER)
26
+    @hapic.output_body(ApplicationSchema(many=True),)
27
+    def applications(self, context, request: TracimRequest, hapic_data=None):
28
+        """
29
+        Get list of alls applications installed in this tracim instance.
30
+        """
31
+        return applications
32
+
33
+    def bind(self, configurator: Configurator) -> None:
34
+        """
35
+        Create all routes and views using pyramid configurator
36
+        for this controller
37
+        """
38
+
39
+        # Applications
40
+        configurator.add_route('applications', '/system/applications', request_method='GET')  # nopep8
41
+        configurator.add_view(self.applications, route_name='applications')
42
+

+ 58 - 0
tracim/views/core_api/user_controller.py 查看文件

1
+from pyramid.config import Configurator
2
+from sqlalchemy.orm.exc import NoResultFound
3
+
4
+from tracim.lib.utils.authorization import require_same_user_or_profile
5
+from tracim.models import Group
6
+from tracim.models.context_models import WorkspaceInContext
7
+
8
+try:  # Python 3.5+
9
+    from http import HTTPStatus
10
+except ImportError:
11
+    from http import client as HTTPStatus
12
+
13
+from tracim import hapic, TracimRequest
14
+
15
+from tracim.exceptions import NotAuthenticated
16
+from tracim.exceptions import InsufficientUserProfile
17
+from tracim.exceptions import UserDoesNotExist
18
+from tracim.lib.core.workspace import WorkspaceApi
19
+from tracim.views.controllers import Controller
20
+from tracim.views.core_api.schemas import UserIdPathSchema
21
+from tracim.views.core_api.schemas import WorkspaceDigestSchema
22
+
23
+
24
+class UserController(Controller):
25
+
26
+    @hapic.with_api_doc()
27
+    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
28
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
29
+    @hapic.handle_exception(UserDoesNotExist, HTTPStatus.NOT_FOUND)
30
+    @require_same_user_or_profile(Group.TIM_ADMIN)
31
+    @hapic.input_path(UserIdPathSchema())
32
+    @hapic.output_body(WorkspaceDigestSchema(many=True),)
33
+    def user_workspace(self, context, request: TracimRequest, hapic_data=None):
34
+        """
35
+        Get list of user workspaces
36
+        """
37
+        app_config = request.registry.settings['CFG']
38
+        wapi = WorkspaceApi(
39
+            current_user=request.current_user,  # User
40
+            session=request.dbsession,
41
+            config=app_config,
42
+        )
43
+        
44
+        workspaces = wapi.get_all_for_user(request.candidate_user)
45
+        return [
46
+            WorkspaceInContext(workspace, request.dbsession, app_config)
47
+            for workspace in workspaces
48
+        ]
49
+
50
+    def bind(self, configurator: Configurator) -> None:
51
+        """
52
+        Create all routes and views using pyramid configurator
53
+        for this controller
54
+        """
55
+
56
+        # Applications
57
+        configurator.add_route('user_workspace', '/users/{user_id}/workspaces', request_method='GET')  # nopep8
58
+        configurator.add_view(self.user_workspace, route_name='user_workspace')

+ 90 - 0
tracim/views/core_api/workspace_controller.py 查看文件

1
+import typing
2
+
3
+from pyramid.config import Configurator
4
+from sqlalchemy.orm.exc import NoResultFound
5
+
6
+from tracim.lib.core.userworkspace import RoleApi
7
+from tracim.lib.utils.authorization import require_workspace_role
8
+from tracim.models.context_models import WorkspaceInContext
9
+from tracim.models.context_models import UserRoleWorkspaceInContext
10
+from tracim.models.data import UserRoleInWorkspace
11
+
12
+try:  # Python 3.5+
13
+    from http import HTTPStatus
14
+except ImportError:
15
+    from http import client as HTTPStatus
16
+
17
+from tracim import hapic, TracimRequest
18
+from tracim.exceptions import NotAuthenticated
19
+from tracim.exceptions import InsufficientUserProfile
20
+from tracim.exceptions import WorkspaceNotFound
21
+from tracim.lib.core.user import UserApi
22
+from tracim.lib.core.workspace import WorkspaceApi
23
+from tracim.views.controllers import Controller
24
+from tracim.views.core_api.schemas import WorkspaceSchema
25
+from tracim.views.core_api.schemas import UserSchema
26
+from tracim.views.core_api.schemas import WorkspaceIdPathSchema
27
+from tracim.views.core_api.schemas import WorkspaceMemberSchema
28
+
29
+class WorkspaceController(Controller):
30
+
31
+    @hapic.with_api_doc()
32
+    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
33
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
34
+    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
35
+    @require_workspace_role(UserRoleInWorkspace.READER)
36
+    @hapic.input_path(WorkspaceIdPathSchema())
37
+    @hapic.output_body(WorkspaceSchema())
38
+    def workspace(self, context, request: TracimRequest, hapic_data=None):
39
+        """
40
+        Get workspace informations
41
+        """
42
+        wid = hapic_data.path['workspace_id']
43
+        app_config = request.registry.settings['CFG']
44
+        wapi = WorkspaceApi(
45
+            current_user=request.current_user,  # User
46
+            session=request.dbsession,
47
+            config=app_config,
48
+        )
49
+        return wapi.get_workspace_with_context(request.current_workspace)
50
+
51
+    @hapic.with_api_doc()
52
+    @hapic.handle_exception(NotAuthenticated, HTTPStatus.UNAUTHORIZED)
53
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
54
+    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
55
+    @require_workspace_role(UserRoleInWorkspace.READER)
56
+    @hapic.input_path(WorkspaceIdPathSchema())
57
+    @hapic.output_body(WorkspaceMemberSchema(many=True))
58
+    def workspaces_members(
59
+            self,
60
+            context,
61
+            request: TracimRequest,
62
+            hapic_data=None
63
+    ) -> typing.List[UserRoleWorkspaceInContext]:
64
+        """
65
+        Get Members of this workspace
66
+        """
67
+        app_config = request.registry.settings['CFG']
68
+        rapi = RoleApi(
69
+            current_user=request.current_user,
70
+            session=request.dbsession,
71
+            config=app_config,
72
+        )
73
+        
74
+        roles = rapi.get_all_for_workspace(request.current_workspace)
75
+        return [
76
+            rapi.get_user_role_workspace_with_context(user_role)
77
+            for user_role in roles
78
+        ]
79
+
80
+    def bind(self, configurator: Configurator) -> None:
81
+        """
82
+        Create all routes and views using
83
+        pyramid configurator for this controller
84
+        """
85
+
86
+        # Applications
87
+        configurator.add_route('workspace', '/workspaces/{workspace_id}', request_method='GET')  # nopep8
88
+        configurator.add_view(self.workspace, route_name='workspace')
89
+        configurator.add_route('workspace_members', '/workspaces/{workspace_id}/members', request_method='GET')  # nopep8
90
+        configurator.add_view(self.workspaces_members, route_name='workspace_members')  # nopep8