Browse Source

Simpler controller code with some refactoring

Guénaël Muller 6 years ago
parent
commit
cc602e1f03

+ 11 - 3
tracim/lib/core/user.py View File

@@ -46,7 +46,11 @@ class UserApi(object):
46 46
         """
47 47
         Get one user by user id
48 48
         """
49
-        return self._base_query().filter(User.user_id == user_id).one()
49
+        try:
50
+            user = self._base_query().filter(User.user_id == user_id).one()
51
+        except NoResultFound:
52
+            raise UserNotExist()
53
+        return user
50 54
 
51 55
     def get_one_by_email(self, email: str) -> User:
52 56
         """
@@ -54,7 +58,11 @@ class UserApi(object):
54 58
         :param email: Email of the user
55 59
         :return: one user
56 60
         """
57
-        return self._base_query().filter(User.email == email).one()
61
+        try:
62
+            user = self._base_query().filter(User.email == email).one()
63
+        except NoResultFound:
64
+            raise UserNotExist()
65
+        return user
58 66
 
59 67
     # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
60 68
     def get_one_by_id(self, id: int) -> User:
@@ -95,7 +103,7 @@ class UserApi(object):
95 103
                 return user
96 104
             else:
97 105
                 raise WrongUserPassword()
98
-        except (WrongUserPassword, NoResultFound):
106
+        except (WrongUserPassword, NoResultFound, UserNotExist):
99 107
             raise AuthenticationFailed()
100 108
 
101 109
     def can_see_private_info_of_user(self, user: User):

+ 4 - 4
tracim/lib/core/userworkspace.py View File

@@ -120,8 +120,8 @@ class RoleApi(object):
120 120
         return self._session.query(UserRoleInWorkspace)\
121 121
             .filter(UserRoleInWorkspace.user_id == user_id)
122 122
 
123
-    def get_all_for_user(self, user_id):
124
-        return self._get_all_for_user(user_id).all()
123
+    def get_all_for_user(self, user: User):
124
+        return self._get_all_for_user(user.user_id).all()
125 125
 
126 126
     def get_all_for_user_order_by_workspace(
127 127
             self,
@@ -130,9 +130,9 @@ class RoleApi(object):
130 130
         return self._get_all_for_user(user_id)\
131 131
             .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()
132 132
 
133
-    def get_all_for_workspace(self, workspace_id):
133
+    def get_all_for_workspace(self, workspace:Workspace):
134 134
         return self._session.query(UserRoleInWorkspace)\
135
-            .filter(UserRoleInWorkspace.workspace_id == workspace_id).all()
135
+            .filter(UserRoleInWorkspace.workspace_id == workspace.workspace_id).all()  # nopep8
136 136
 
137 137
     def save(self, role: UserRoleInWorkspace):
138 138
         self._session.flush()

+ 2 - 1
tracim/lib/utils/authentification.py View File

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

+ 1 - 1
tracim/lib/utils/authorization.py View File

@@ -80,4 +80,4 @@ def require_workspace_role(minimal_required_role):
80 80
             raise InsufficientUserWorkspaceRole()
81 81
 
82 82
         return wrapper
83
-    return decorator
83
+    return decorator

+ 4 - 4
tracim/lib/utils/request.py View File

@@ -74,7 +74,6 @@ class TracimRequest(Request):
74 74
             )
75 75
         self._current_user = user
76 76
 
77
-
78 77
 ###
79 78
 # Utils for TracimRequest
80 79
 ###
@@ -112,9 +111,10 @@ def get_workspace(
112 111
     """
113 112
     workspace_id = ''
114 113
     try:
115
-        if 'workspace_id' not in request.json_body:
116
-            raise WorkspaceNotFound('No workspace_id param in json body')
117
-        workspace_id = request.json_body['workspace_id']
114
+        if 'workspace_id' in request.matchdict:
115
+            workspace_id = request.matchdict['workspace_id']
116
+        if not workspace_id:
117
+            raise WorkspaceNotFound('No workspace_id param')
118 118
         wapi = WorkspaceApi(
119 119
             current_user=user,
120 120
             session=request.dbsession,

+ 21 - 8
tracim/tests/functional/test_system.py View File

@@ -4,14 +4,13 @@ from tracim.tests import FunctionalTest
4 4
 
5 5
 class TestApplicationsEndpoint(FunctionalTest):
6 6
     def test_api__get_applications__ok_200__nominal_case(self):
7
-        # TODO need authorization ? check permissions ?
8
-        # self.testapp.authorization = (
9
-        #     'Basic',
10
-        #     (
11
-        #         'admin@admin.admin',
12
-        #         'admin@admin.admin'
13
-        #     )
14
-        # )
7
+        self.testapp.authorization = (
8
+            'Basic',
9
+            (
10
+                'admin@admin.admin',
11
+                'admin@admin.admin'
12
+            )
13
+        )
15 14
         res = self.testapp.get('/api/v2/system/applications', status=200)
16 15
         res = res.json_body
17 16
         application = res[0]
@@ -49,3 +48,17 @@ class TestApplicationsEndpoint(FunctionalTest):
49 48
         assert application['hexcolor'] == '#757575'
50 49
         assert application['is_active'] is True
51 50
         assert 'config' in application
51
+
52
+    def test_api__get_workspace__err_401__unregistered_user(self):
53
+        self.testapp.authorization = (
54
+            'Basic',
55
+            (
56
+                'john@doe.doe',
57
+                'lapin'
58
+            )
59
+        )
60
+        res = self.testapp.get('/api/v2/system/applications', status=401)
61
+        assert isinstance(res.json, dict)
62
+        assert 'code' in res.json.keys()
63
+        assert 'message' in res.json.keys()
64
+        assert 'details' in res.json.keys()

+ 30 - 33
tracim/tests/functional/test_workspaces.py View File

@@ -74,20 +74,19 @@ class TestWorkspaceEndpoint(FunctionalTest):
74 74
         assert sidebar_entry['hexcolor'] == "#757575"
75 75
         assert sidebar_entry['icon'] == "calendar-alt"
76 76
 
77
-    # TODO - G.M - 22-05-2018 - Check if this feature is needed
78
-    # def test_api__get_workspace__err_403__unallowed_user(self):
79
-    #     self.testapp.authorization = (
80
-    #         'Basic',
81
-    #         (
82
-    #             'lawrence-not-real-email@fsf.local',
83
-    #             'foobarbaz'
84
-    #         )
85
-    #     )
86
-    #     res = self.testapp.get('/api/v2/workspaces/1', status=403)
87
-    #     assert isinstance(res.json, dict)
88
-    #     assert 'code' in res.json.keys()
89
-    #     assert 'message' in res.json.keys()
90
-    #     assert 'details' in res.json.keys()
77
+    def test_api__get_workspace__err_403__unallowed_user(self):
78
+        self.testapp.authorization = (
79
+            'Basic',
80
+            (
81
+                'lawrence-not-real-email@fsf.local',
82
+                'foobarbaz'
83
+            )
84
+        )
85
+        res = self.testapp.get('/api/v2/workspaces/1', status=403)
86
+        assert isinstance(res.json, dict)
87
+        assert 'code' in res.json.keys()
88
+        assert 'message' in res.json.keys()
89
+        assert 'details' in res.json.keys()
91 90
 
92 91
     def test_api__get_workspace__err_401__unregistered_user(self):
93 92
         self.testapp.authorization = (
@@ -103,7 +102,7 @@ class TestWorkspaceEndpoint(FunctionalTest):
103 102
         assert 'message' in res.json.keys()
104 103
         assert 'details' in res.json.keys()
105 104
 
106
-    def test_api__get_workspace__err_404__workspace_does_not_exist(self):
105
+    def test_api__get_workspace__err_403__workspace_does_not_exist(self):
107 106
         self.testapp.authorization = (
108 107
             'Basic',
109 108
             (
@@ -111,7 +110,7 @@ class TestWorkspaceEndpoint(FunctionalTest):
111 110
                 'admin@admin.admin'
112 111
             )
113 112
         )
114
-        res = self.testapp.get('/api/v2/workspaces/5', status=404)
113
+        res = self.testapp.get('/api/v2/workspaces/5', status=403)
115 114
         assert isinstance(res.json, dict)
116 115
         assert 'code' in res.json.keys()
117 116
         assert 'message' in res.json.keys()
@@ -139,21 +138,19 @@ class TestWorkspaceMembersEndpoint(FunctionalTest):
139 138
         assert user_role['user']['display_name'] == 'Global manager'
140 139
         assert user_role['user']['avatar_url'] is None  # TODO
141 140
 
142
-
143
-
144
-    # def test_api__get_workspace_members__err_400__unallowed_user(self):
145
-    #     self.testapp.authorization = (
146
-    #         'Basic',
147
-    #         (
148
-    #             'lawrence-not-real-email@fsf.local',
149
-    #             'foobarbaz'
150
-    #         )
151
-    #     )
152
-    #     res = self.testapp.get('/api/v2/workspaces/3/members', status=403)
153
-    #     assert isinstance(res.json, dict)
154
-    #     assert 'code' in res.json.keys()
155
-    #     assert 'message' in res.json.keys()
156
-    #     assert 'details' in res.json.keys()
141
+    def test_api__get_workspace_members__err_403__unallowed_user(self):
142
+        self.testapp.authorization = (
143
+            'Basic',
144
+            (
145
+                'lawrence-not-real-email@fsf.local',
146
+                'foobarbaz'
147
+            )
148
+        )
149
+        res = self.testapp.get('/api/v2/workspaces/3/members', status=403)
150
+        assert isinstance(res.json, dict)
151
+        assert 'code' in res.json.keys()
152
+        assert 'message' in res.json.keys()
153
+        assert 'details' in res.json.keys()
157 154
 
158 155
     def test_api__get_workspace_members__err_401__unregistered_user(self):
159 156
         self.testapp.authorization = (
@@ -169,7 +166,7 @@ class TestWorkspaceMembersEndpoint(FunctionalTest):
169 166
         assert 'message' in res.json.keys()
170 167
         assert 'details' in res.json.keys()
171 168
 
172
-    def test_api__get_workspace_members__err_404__workspace_does_not_exist(self):
169
+    def test_api__get_workspace_members__err_403__workspace_does_not_exist(self):
173 170
         self.testapp.authorization = (
174 171
             'Basic',
175 172
             (
@@ -177,7 +174,7 @@ class TestWorkspaceMembersEndpoint(FunctionalTest):
177 174
                 'admin@admin.admin'
178 175
             )
179 176
         )
180
-        res = self.testapp.get('/api/v2/workspaces/5/members', status=404)
177
+        res = self.testapp.get('/api/v2/workspaces/5/members', status=403)
181 178
         assert isinstance(res.json, dict)
182 179
         assert 'code' in res.json.keys()
183 180
         assert 'message' in res.json.keys()

+ 2 - 2
tracim/tests/library/test_user_api.py View File

@@ -60,7 +60,7 @@ class TestUserApi(DefaultTest):
60 60
             session=self.session,
61 61
             config=self.config,
62 62
         )
63
-        with pytest.raises(NoResultFound):
63
+        with pytest.raises(UserNotExist):
64 64
             api.get_one_by_email('unknown')
65 65
 
66 66
     # def test_unit__get_all__ok__nominal_case(self):
@@ -156,4 +156,4 @@ class TestUserApi(DefaultTest):
156 156
             config=self.config,
157 157
         )
158 158
         with pytest.raises(AuthenticationFailed):
159
-            api.authenticate_user('unknown_user', 'wrong_password')
159
+            api.authenticate_user('admin@admin.admin', 'wrong_password')

+ 6 - 0
tracim/views/core_api/system_controller.py View File

@@ -1,6 +1,9 @@
1 1
 # coding=utf-8
2 2
 from pyramid.config import Configurator
3 3
 
4
+from tracim.exceptions import NotAuthentificated, InsufficientUserProfile
5
+from tracim.lib.utils.authorization import require_profile
6
+from tracim.models import Group
4 7
 from tracim.models.applications import applications
5 8
 
6 9
 try:  # Python 3.5+
@@ -17,6 +20,9 @@ from tracim.views.core_api.schemas import ApplicationSchema
17 20
 class SystemController(Controller):
18 21
 
19 22
     @hapic.with_api_doc()
23
+    @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
24
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
25
+    @require_profile(Group.TIM_USER)
20 26
     @hapic.output_body(ApplicationSchema(many=True),)
21 27
     def applications(self, context, request: TracimRequest, hapic_data=None):
22 28
         """

+ 6 - 10
tracim/views/core_api/user_controller.py View File

@@ -30,27 +30,23 @@ class UserController(Controller):
30 30
         """
31 31
         Get list of user workspaces
32 32
         """
33
-        uid = hapic_data.path['user_id']
34 33
         app_config = request.registry.settings['CFG']
34
+
35
+        uid = hapic_data.path['user_id']
35 36
         uapi = UserApi(
36 37
             request.current_user,
37 38
             session=request.dbsession,
38 39
             config=app_config,
39 40
         )
41
+        user = uapi.get_one(uid)
42
+        if not uapi.can_see_private_info_of_user(user):
43
+            raise InsufficientUserProfile()
44
+
40 45
         wapi = WorkspaceApi(
41 46
             current_user=request.current_user,  # User
42 47
             session=request.dbsession,
43 48
             config=app_config,
44 49
         )
45
-        # TODO - G.M - 22-05-2018 - Refactor this in a more lib way( avoid
46
-        # try/catch and complex code here).
47
-        try:
48
-            user = uapi.get_one(uid)
49
-        except NoResultFound:
50
-            raise UserNotExist()
51
-        if not uapi.can_see_private_info_of_user(user):
52
-            raise InsufficientUserProfile()
53
-
54 50
         return [
55 51
             WorkspaceInContext(workspace, request.dbsession, app_config)
56 52
             for workspace in wapi.get_all_for_user(user)

+ 12 - 24
tracim/views/core_api/workspace_controller.py View File

@@ -4,8 +4,10 @@ from pyramid.config import Configurator
4 4
 from sqlalchemy.orm.exc import NoResultFound
5 5
 
6 6
 from tracim.lib.core.userworkspace import RoleApi
7
+from tracim.lib.utils.authorization import require_workspace_role
7 8
 from tracim.models.context_models import WorkspaceInContext, \
8 9
     UserRoleWorkspaceInContext
10
+from tracim.models.data import UserRoleInWorkspace
9 11
 
10 12
 try:  # Python 3.5+
11 13
     from http import HTTPStatus
@@ -25,10 +27,11 @@ from tracim.views.core_api.schemas import WorkspaceSchema, UserSchema, \
25 27
 class WorkspaceController(Controller):
26 28
 
27 29
     @hapic.with_api_doc()
28
-    @hapic.input_path(WorkspaceIdPathSchema())
29 30
     @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
30
-    #@hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
31
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.NOT_FOUND)
31
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
32
+    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
33
+    @require_workspace_role(UserRoleInWorkspace.READER)
34
+    @hapic.input_path(WorkspaceIdPathSchema())
32 35
     @hapic.output_body(WorkspaceSchema())
33 36
     def workspace(self, context, request: TracimRequest, hapic_data=None):
34 37
         """
@@ -41,19 +44,14 @@ class WorkspaceController(Controller):
41 44
             session=request.dbsession,
42 45
             config=app_config,
43 46
         )
44
-        # TODO - G.M - 22-05-2018 - Refactor this in a more lib way( avoid
45
-        # try/catch and complex code here).
46
-        try:
47
-            workspace = wapi.get_one(wid)
48
-        except NoResultFound:
49
-            raise WorkspaceNotFound()
50
-        return wapi.get_workspace_with_context(workspace)
47
+        return wapi.get_workspace_with_context(request.current_workspace)
51 48
 
52 49
     @hapic.with_api_doc()
53
-    @hapic.input_path(WorkspaceIdPathSchema())
54 50
     @hapic.handle_exception(NotAuthentificated, HTTPStatus.UNAUTHORIZED)
55
-    #@hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
56
-    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.NOT_FOUND)
51
+    @hapic.handle_exception(InsufficientUserProfile, HTTPStatus.FORBIDDEN)
52
+    @hapic.handle_exception(WorkspaceNotFound, HTTPStatus.FORBIDDEN)
53
+    @require_workspace_role(UserRoleInWorkspace.READER)
54
+    @hapic.input_path(WorkspaceIdPathSchema())
57 55
     @hapic.output_body(WorkspaceMemberSchema(many=True))
58 56
     def workspaces_members(
59 57
             self,
@@ -64,25 +62,15 @@ class WorkspaceController(Controller):
64 62
         """
65 63
         Get Members of this workspace
66 64
         """
67
-        wid = hapic_data.path['workspace_id']
68 65
         app_config = request.registry.settings['CFG']
69 66
         rapi = RoleApi(
70 67
             current_user=request.current_user,
71 68
             session=request.dbsession,
72 69
             config=app_config,
73 70
         )
74
-        wapi = WorkspaceApi(
75
-            current_user=request.current_user,
76
-            session=request.dbsession,
77
-            config=app_config,
78
-        )
79
-        try:
80
-            wapi.get_one(wid)
81
-        except NoResultFound:
82
-            raise WorkspaceNotFound()
83 71
         return [
84 72
             rapi.get_user_role_workspace_with_context(user_role)
85
-            for user_role in rapi.get_all_for_workspace(wid)
73
+            for user_role in rapi.get_all_for_workspace(request.current_workspace)
86 74
         ]
87 75
 
88 76
     def bind(self, configurator: Configurator) -> None: