Browse Source

Merge pull request #3 from tracim/feature/612_get_known_user

Bastien Sevajol 5 years ago
parent
commit
a074379819
No account linked to committer's email

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

@@ -203,3 +203,7 @@ class PageOfPreviewNotFound(NotFound):
203 203
 
204 204
 class PreviewDimNotAllowed(TracimException):
205 205
     pass
206
+
207
+
208
+class TooShortAutocompleteString(TracimException):
209
+    pass

+ 40 - 2
backend/tracim_backend/lib/core/user.py View File

@@ -3,13 +3,17 @@ from smtplib import SMTPException
3 3
 
4 4
 import transaction
5 5
 import typing as typing
6
+
7
+from sqlalchemy import or_
6 8
 from sqlalchemy.orm import Session
9
+from sqlalchemy.orm import Query
7 10
 from sqlalchemy.orm.exc import NoResultFound
8 11
 
9 12
 from tracim_backend import CFG
10 13
 from tracim_backend.models.auth import User
11 14
 from tracim_backend.models.auth import Group
12 15
 from tracim_backend.exceptions import NoUserSetted
16
+from tracim_backend.exceptions import TooShortAutocompleteString
13 17
 from tracim_backend.exceptions import PasswordDoNotMatch
14 18
 from tracim_backend.exceptions import EmailValidationFailed
15 19
 from tracim_backend.exceptions import UserDoesNotExist
@@ -20,6 +24,7 @@ from tracim_backend.exceptions import UserNotActive
20 24
 from tracim_backend.models.context_models import UserInContext
21 25
 from tracim_backend.lib.mail_notifier.notifier import get_email_manager
22 26
 from tracim_backend.models.context_models import TypeUser
27
+from tracim_backend.models.data import UserRoleInWorkspace
23 28
 
24 29
 
25 30
 class UserApi(object):
@@ -94,8 +99,41 @@ class UserApi(object):
94 99
             raise UserDoesNotExist('There is no current user')
95 100
         return self._user
96 101
 
102
+    def _get_all_query(self) -> Query:
103
+        return self._session.query(User).order_by(User.display_name)
104
+
97 105
     def get_all(self) -> typing.Iterable[User]:
98
-        return self._session.query(User).order_by(User.display_name).all()
106
+        return self._get_all_query().all()
107
+
108
+    def get_known_user(
109
+            self,
110
+            acp: str,
111
+    ) -> typing.Iterable[User]:
112
+        """
113
+        Return list of know user by current UserApi user.
114
+        :param acp: autocomplete filter by name/email
115
+        :return: List of found users
116
+        """
117
+        if len(acp) < 2:
118
+            raise TooShortAutocompleteString(
119
+                '"{acp}" is a too short string, acp string need to have more than one character'.format(acp=acp)  # nopep8
120
+            )
121
+        query = self._get_all_query()
122
+        query = query.filter(or_(User.display_name.ilike('%{}%'.format(acp)), User.email.ilike('%{}%'.format(acp))))  # nopep8
123
+
124
+        # INFO - G.M - 2018-07-27 - if user is set and is simple user, we
125
+        # should show only user in same workspace as user
126
+        if self._user and self._user.profile.id <= Group.TIM_USER:
127
+            user_workspaces_id_query = self._session.\
128
+                query(UserRoleInWorkspace.workspace_id).\
129
+                distinct(UserRoleInWorkspace.workspace_id).\
130
+                filter(UserRoleInWorkspace.user_id == self._user.user_id)
131
+            users_in_workspaces = self._session.\
132
+                query(UserRoleInWorkspace.user_id).\
133
+                distinct(UserRoleInWorkspace.user_id).\
134
+                filter(UserRoleInWorkspace.workspace_id.in_(user_workspaces_id_query.subquery())).subquery()  # nopep8
135
+            query = query.filter(User.user_id.in_(users_in_workspaces))
136
+        return query.all()
99 137
 
100 138
     def find(
101 139
             self,
@@ -196,7 +234,7 @@ class UserApi(object):
196 234
         )
197 235
         if do_save:
198 236
             # TODO - G.M - 2018-07-24 - Check why commit is needed here
199
-            transaction.commit()
237
+            self.save(user)
200 238
         return user
201 239
 
202 240
     def set_email(

+ 8 - 0
backend/tracim_backend/models/context_models.py View File

@@ -186,6 +186,14 @@ class CommentPath(object):
186 186
         self.comment_id = comment_id
187 187
 
188 188
 
189
+class AutocompleteQuery(object):
190
+    """
191
+    Autocomplete query model
192
+    """
193
+    def __init__(self, acp: str):
194
+        self.acp = acp
195
+
196
+
189 197
 class PageQuery(object):
190 198
     """
191 199
     Page query model

+ 408 - 0
backend/tracim_backend/tests/functional/test_user.py View File

@@ -2646,6 +2646,390 @@ class TestUserEndpoint(FunctionalTest):
2646 2646
         )
2647 2647
 
2648 2648
 
2649
+class TestUsersEndpoint(FunctionalTest):
2650
+    # -*- coding: utf-8 -*-
2651
+    """
2652
+    Tests for GET /api/v2/users/{user_id}
2653
+    """
2654
+    fixtures = [BaseFixture]
2655
+
2656
+    def test_api__get_user__ok_200__admin(self):
2657
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2658
+        admin = dbsession.query(models.User) \
2659
+            .filter(models.User.email == 'admin@admin.admin') \
2660
+            .one()
2661
+        uapi = UserApi(
2662
+            current_user=admin,
2663
+            session=dbsession,
2664
+            config=self.app_config,
2665
+        )
2666
+        gapi = GroupApi(
2667
+            current_user=admin,
2668
+            session=dbsession,
2669
+            config=self.app_config,
2670
+        )
2671
+        groups = [gapi.get_one_with_name('users')]
2672
+        test_user = uapi.create_user(
2673
+            email='test@test.test',
2674
+            password='pass',
2675
+            name='bob',
2676
+            groups=groups,
2677
+            timezone='Europe/Paris',
2678
+            do_save=True,
2679
+            do_notify=False,
2680
+        )
2681
+        uapi.save(test_user)
2682
+        transaction.commit()
2683
+        user_id = int(test_user.user_id)
2684
+
2685
+        self.testapp.authorization = (
2686
+            'Basic',
2687
+            (
2688
+                'admin@admin.admin',
2689
+                'admin@admin.admin'
2690
+            )
2691
+        )
2692
+        res = self.testapp.get(
2693
+            '/api/v2/users',
2694
+            status=200
2695
+        )
2696
+        res = res.json_body
2697
+        assert len(res) == 2
2698
+        assert res[0]['user_id'] == admin.user_id
2699
+        assert res[0]['public_name'] == admin.display_name
2700
+        assert res[0]['avatar_url'] is None
2701
+
2702
+        assert res[1]['user_id'] == test_user.user_id
2703
+        assert res[1]['public_name'] == test_user.display_name
2704
+        assert res[1]['avatar_url'] is None
2705
+
2706
+    def test_api__get_user__err_403__normal_user(self):
2707
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2708
+        admin = dbsession.query(models.User) \
2709
+            .filter(models.User.email == 'admin@admin.admin') \
2710
+            .one()
2711
+        uapi = UserApi(
2712
+            current_user=admin,
2713
+            session=dbsession,
2714
+            config=self.app_config,
2715
+        )
2716
+        gapi = GroupApi(
2717
+            current_user=admin,
2718
+            session=dbsession,
2719
+            config=self.app_config,
2720
+        )
2721
+        groups = [gapi.get_one_with_name('users')]
2722
+        test_user = uapi.create_user(
2723
+            email='test@test.test',
2724
+            password='pass',
2725
+            name='bob',
2726
+            groups=groups,
2727
+            timezone='Europe/Paris',
2728
+            do_save=True,
2729
+            do_notify=False,
2730
+        )
2731
+        uapi.save(test_user)
2732
+        transaction.commit()
2733
+        user_id = int(test_user.user_id)
2734
+
2735
+        self.testapp.authorization = (
2736
+            'Basic',
2737
+            (
2738
+                'test@test.test',
2739
+                'pass'
2740
+            )
2741
+        )
2742
+        self.testapp.get(
2743
+            '/api/v2/users',
2744
+            status=403
2745
+        )
2746
+
2747
+
2748
+class TestKnownMembersEndpoint(FunctionalTest):
2749
+    # -*- coding: utf-8 -*-
2750
+    """
2751
+    Tests for GET /api/v2/users/{user_id}
2752
+    """
2753
+    fixtures = [BaseFixture]
2754
+
2755
+    def test_api__get_user__ok_200__admin__by_name(self):
2756
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2757
+        admin = dbsession.query(models.User) \
2758
+            .filter(models.User.email == 'admin@admin.admin') \
2759
+            .one()
2760
+        uapi = UserApi(
2761
+            current_user=admin,
2762
+            session=dbsession,
2763
+            config=self.app_config,
2764
+        )
2765
+        gapi = GroupApi(
2766
+            current_user=admin,
2767
+            session=dbsession,
2768
+            config=self.app_config,
2769
+        )
2770
+        groups = [gapi.get_one_with_name('users')]
2771
+        test_user = uapi.create_user(
2772
+            email='test@test.test',
2773
+            password='pass',
2774
+            name='bob',
2775
+            groups=groups,
2776
+            timezone='Europe/Paris',
2777
+            do_save=True,
2778
+            do_notify=False,
2779
+        )
2780
+        test_user2 = uapi.create_user(
2781
+            email='test2@test2.test2',
2782
+            password='pass',
2783
+            name='bob2',
2784
+            groups=groups,
2785
+            timezone='Europe/Paris',
2786
+            do_save=True,
2787
+            do_notify=False,
2788
+        )
2789
+        uapi.save(test_user)
2790
+        uapi.save(test_user2)
2791
+        transaction.commit()
2792
+        user_id = int(admin.user_id)
2793
+
2794
+        self.testapp.authorization = (
2795
+            'Basic',
2796
+            (
2797
+                'admin@admin.admin',
2798
+                'admin@admin.admin'
2799
+            )
2800
+        )
2801
+        params = {
2802
+            'acp': 'bob',
2803
+        }
2804
+        res = self.testapp.get(
2805
+            '/api/v2/users/{user_id}/known_members'.format(user_id=user_id),
2806
+            status=200,
2807
+            params=params,
2808
+        )
2809
+        res = res.json_body
2810
+        assert len(res) == 2
2811
+        assert res[0]['user_id'] == test_user.user_id
2812
+        assert res[0]['public_name'] == test_user.display_name
2813
+        assert res[0]['avatar_url'] is None
2814
+
2815
+        assert res[1]['user_id'] == test_user2.user_id
2816
+        assert res[1]['public_name'] == test_user2.display_name
2817
+        assert res[1]['avatar_url'] is None
2818
+
2819
+    def test_api__get_user__ok_200__admin__by_email(self):
2820
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2821
+        admin = dbsession.query(models.User) \
2822
+            .filter(models.User.email == 'admin@admin.admin') \
2823
+            .one()
2824
+        uapi = UserApi(
2825
+            current_user=admin,
2826
+            session=dbsession,
2827
+            config=self.app_config,
2828
+        )
2829
+        gapi = GroupApi(
2830
+            current_user=admin,
2831
+            session=dbsession,
2832
+            config=self.app_config,
2833
+        )
2834
+        groups = [gapi.get_one_with_name('users')]
2835
+        test_user = uapi.create_user(
2836
+            email='test@test.test',
2837
+            password='pass',
2838
+            name='bob',
2839
+            groups=groups,
2840
+            timezone='Europe/Paris',
2841
+            do_save=True,
2842
+            do_notify=False,
2843
+        )
2844
+        test_user2 = uapi.create_user(
2845
+            email='test2@test2.test2',
2846
+            password='pass',
2847
+            name='bob2',
2848
+            groups=groups,
2849
+            timezone='Europe/Paris',
2850
+            do_save=True,
2851
+            do_notify=False,
2852
+        )
2853
+        uapi.save(test_user)
2854
+        uapi.save(test_user2)
2855
+        transaction.commit()
2856
+        user_id = int(admin.user_id)
2857
+
2858
+        self.testapp.authorization = (
2859
+            'Basic',
2860
+            (
2861
+                'admin@admin.admin',
2862
+                'admin@admin.admin'
2863
+            )
2864
+        )
2865
+        params = {
2866
+            'acp': 'test',
2867
+        }
2868
+        res = self.testapp.get(
2869
+            '/api/v2/users/{user_id}/known_members'.format(user_id=user_id),
2870
+            status=200,
2871
+            params=params,
2872
+        )
2873
+        res = res.json_body
2874
+        assert len(res) == 2
2875
+        assert res[0]['user_id'] == test_user.user_id
2876
+        assert res[0]['public_name'] == test_user.display_name
2877
+        assert res[0]['avatar_url'] is None
2878
+
2879
+        assert res[1]['user_id'] == test_user2.user_id
2880
+        assert res[1]['public_name'] == test_user2.display_name
2881
+        assert res[1]['avatar_url'] is None
2882
+
2883
+    def test_api__get_user__err_403__admin__too_small_acp(self):
2884
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2885
+        admin = dbsession.query(models.User) \
2886
+            .filter(models.User.email == 'admin@admin.admin') \
2887
+            .one()
2888
+        uapi = UserApi(
2889
+            current_user=admin,
2890
+            session=dbsession,
2891
+            config=self.app_config,
2892
+        )
2893
+        gapi = GroupApi(
2894
+            current_user=admin,
2895
+            session=dbsession,
2896
+            config=self.app_config,
2897
+        )
2898
+        groups = [gapi.get_one_with_name('users')]
2899
+        test_user = uapi.create_user(
2900
+            email='test@test.test',
2901
+            password='pass',
2902
+            name='bob',
2903
+            groups=groups,
2904
+            timezone='Europe/Paris',
2905
+            do_save=True,
2906
+            do_notify=False,
2907
+        )
2908
+        test_user2 = uapi.create_user(
2909
+            email='test2@test2.test2',
2910
+            password='pass',
2911
+            name='bob2',
2912
+            groups=groups,
2913
+            timezone='Europe/Paris',
2914
+            do_save=True,
2915
+            do_notify=False,
2916
+        )
2917
+        uapi.save(test_user)
2918
+        transaction.commit()
2919
+        user_id = int(admin.user_id)
2920
+
2921
+        self.testapp.authorization = (
2922
+            'Basic',
2923
+            (
2924
+                'admin@admin.admin',
2925
+                'admin@admin.admin'
2926
+            )
2927
+        )
2928
+        params = {
2929
+            'acp': 't',
2930
+        }
2931
+        res = self.testapp.get(
2932
+            '/api/v2/users/{user_id}/known_members'.format(user_id=user_id),
2933
+            status=400,
2934
+            params=params
2935
+        )
2936
+
2937
+    def test_api__get_user__ok_200__normal_user_by_email(self):
2938
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
2939
+        admin = dbsession.query(models.User) \
2940
+            .filter(models.User.email == 'admin@admin.admin') \
2941
+            .one()
2942
+        uapi = UserApi(
2943
+            current_user=admin,
2944
+            session=dbsession,
2945
+            config=self.app_config,
2946
+        )
2947
+        gapi = GroupApi(
2948
+            current_user=admin,
2949
+            session=dbsession,
2950
+            config=self.app_config,
2951
+        )
2952
+        groups = [gapi.get_one_with_name('users')]
2953
+        test_user = uapi.create_user(
2954
+            email='test@test.test',
2955
+            password='pass',
2956
+            name='bob',
2957
+            groups=groups,
2958
+            timezone='Europe/Paris',
2959
+            do_save=True,
2960
+            do_notify=False,
2961
+        )
2962
+        test_user2 = uapi.create_user(
2963
+            email='test2@test2.test2',
2964
+            password='pass',
2965
+            name='bob2',
2966
+            groups=groups,
2967
+            timezone='Europe/Paris',
2968
+            do_save=True,
2969
+            do_notify=False,
2970
+        )
2971
+        test_user3 = uapi.create_user(
2972
+            email='test3@test3.test3',
2973
+            password='pass',
2974
+            name='bob3',
2975
+            groups=groups,
2976
+            timezone='Europe/Paris',
2977
+            do_save=True,
2978
+            do_notify=False,
2979
+        )
2980
+        uapi.save(test_user)
2981
+        uapi.save(test_user2)
2982
+        uapi.save(test_user3)
2983
+        workspace_api = WorkspaceApi(
2984
+            current_user=admin,
2985
+            session=dbsession,
2986
+            config=self.app_config
2987
+
2988
+        )
2989
+        workspace = WorkspaceApi(
2990
+            current_user=admin,
2991
+            session=dbsession,
2992
+            config=self.app_config,
2993
+        ).create_workspace(
2994
+            'test workspace',
2995
+            save_now=True
2996
+        )
2997
+        role_api = RoleApi(
2998
+            current_user=admin,
2999
+            session=dbsession,
3000
+            config=self.app_config,
3001
+        )
3002
+        role_api.create_one(test_user, workspace, UserRoleInWorkspace.READER, False)
3003
+        role_api.create_one(test_user2, workspace, UserRoleInWorkspace.READER, False)
3004
+        transaction.commit()
3005
+        user_id = int(test_user.user_id)
3006
+
3007
+        self.testapp.authorization = (
3008
+            'Basic',
3009
+            (
3010
+                'test@test.test',
3011
+                'pass'
3012
+            )
3013
+        )
3014
+        params = {
3015
+            'acp': 'test',
3016
+        }
3017
+        res = self.testapp.get(
3018
+            '/api/v2/users/{user_id}/known_members'.format(user_id=user_id),
3019
+            status=200,
3020
+            params=params
3021
+        )
3022
+        res = res.json_body
3023
+        assert len(res) == 2
3024
+        assert res[0]['user_id'] == test_user.user_id
3025
+        assert res[0]['public_name'] == test_user.display_name
3026
+        assert res[0]['avatar_url'] is None
3027
+
3028
+        assert res[1]['user_id'] == test_user2.user_id
3029
+        assert res[1]['public_name'] == test_user2.display_name
3030
+        assert res[1]['avatar_url'] is None
3031
+
3032
+
2649 3033
 class TestSetEmailEndpoint(FunctionalTest):
2650 3034
     # -*- coding: utf-8 -*-
2651 3035
     """
@@ -3025,6 +3409,12 @@ class TestSetPasswordEndpoint(FunctionalTest):
3025 3409
             status=204,
3026 3410
         )
3027 3411
         # Check After
3412
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
3413
+        uapi = UserApi(
3414
+            current_user=admin,
3415
+            session=dbsession,
3416
+            config=self.app_config,
3417
+        )
3028 3418
         user = uapi.get_one(user_id)
3029 3419
         assert not user.validate_password('pass')
3030 3420
         assert user.validate_password('mynewpassword')
@@ -3080,6 +3470,12 @@ class TestSetPasswordEndpoint(FunctionalTest):
3080 3470
             params=params,
3081 3471
             status=403,
3082 3472
         )
3473
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
3474
+        uapi = UserApi(
3475
+            current_user=admin,
3476
+            session=dbsession,
3477
+            config=self.app_config,
3478
+        )
3083 3479
         # Check After
3084 3480
         user = uapi.get_one(user_id)
3085 3481
         assert user.validate_password('pass')
@@ -3138,6 +3534,12 @@ class TestSetPasswordEndpoint(FunctionalTest):
3138 3534
             status=400,
3139 3535
         )
3140 3536
         # Check After
3537
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
3538
+        uapi = UserApi(
3539
+            current_user=admin,
3540
+            session=dbsession,
3541
+            config=self.app_config,
3542
+        )
3141 3543
         user = uapi.get_one(user_id)
3142 3544
         assert user.validate_password('pass')
3143 3545
         assert not user.validate_password('mynewpassword')
@@ -3195,6 +3597,12 @@ class TestSetPasswordEndpoint(FunctionalTest):
3195 3597
             status=204,
3196 3598
         )
3197 3599
         # Check After
3600
+        dbsession = get_tm_session(self.session_factory, transaction.manager)
3601
+        uapi = UserApi(
3602
+            current_user=admin,
3603
+            session=dbsession,
3604
+            config=self.app_config,
3605
+        )
3198 3606
         user = uapi.get_one(user_id)
3199 3607
         assert not user.validate_password('pass')
3200 3608
         assert user.validate_password('mynewpassword')

+ 183 - 0
backend/tracim_backend/tests/library/test_user_api.py View File

@@ -1,14 +1,19 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import pytest
3 3
 import transaction
4
+from tracim_backend import models
4 5
 
5 6
 from tracim_backend.exceptions import AuthenticationFailed
7
+from tracim_backend.exceptions import TooShortAutocompleteString
6 8
 from tracim_backend.exceptions import UserDoesNotExist
7 9
 from tracim_backend.exceptions import UserNotActive
8 10
 from tracim_backend.lib.core.group import GroupApi
9 11
 from tracim_backend.lib.core.user import UserApi
12
+from tracim_backend.lib.core.userworkspace import RoleApi
13
+from tracim_backend.lib.core.workspace import WorkspaceApi
10 14
 from tracim_backend.models import User
11 15
 from tracim_backend.models.context_models import UserInContext
16
+from tracim_backend.models.data import UserRoleInWorkspace
12 17
 from tracim_backend.tests import DefaultTest
13 18
 from tracim_backend.tests import eq_
14 19
 
@@ -107,6 +112,184 @@ class TestUserApi(DefaultTest):
107 112
         # u1 + Admin user from BaseFixture
108 113
         assert 2 == len(users)
109 114
 
115
+    def test_unit__get_known__user__admin__too_short_acp_str(self):
116
+        api = UserApi(
117
+            current_user=None,
118
+            session=self.session,
119
+            config=self.config,
120
+        )
121
+        u1 = api.create_user(
122
+            email='email@email',
123
+            name='name',
124
+            do_notify=False,
125
+            do_save=True,
126
+        )
127
+        with pytest.raises(TooShortAutocompleteString):
128
+            api.get_known_user('e')
129
+
130
+    def test_unit__get_known__user__admin__by_email(self):
131
+        api = UserApi(
132
+            current_user=None,
133
+            session=self.session,
134
+            config=self.config,
135
+        )
136
+        u1 = api.create_user(
137
+            email='email@email',
138
+            name='name',
139
+            do_notify=False,
140
+            do_save=True,
141
+        )
142
+
143
+        users = api.get_known_user('email')
144
+        assert len(users) == 1
145
+        assert users[0] == u1
146
+
147
+    def test_unit__get_known__user__user__no_workspace_empty_known_user(self):
148
+        admin = self.session.query(models.User) \
149
+            .filter(models.User.email == 'admin@admin.admin') \
150
+            .one()
151
+        api = UserApi(
152
+            current_user=admin,
153
+            session=self.session,
154
+            config=self.config,
155
+        )
156
+        u1 = api.create_user(
157
+            email='email@email',
158
+            name='name',
159
+            do_notify=False,
160
+            do_save=True,
161
+        )
162
+        api2 = UserApi(
163
+            current_user=u1,
164
+            session=self.session,
165
+            config=self.config,
166
+        )
167
+        users = api2.get_known_user('email')
168
+        assert len(users) == 0
169
+
170
+    def test_unit__get_known__user__same_workspaces_users_by_name(self):
171
+        admin = self.session.query(models.User) \
172
+            .filter(models.User.email == 'admin@admin.admin') \
173
+            .one()
174
+        api = UserApi(
175
+            current_user=None,
176
+            session=self.session,
177
+            config=self.config,
178
+        )
179
+        u1 = api.create_user(
180
+            email='email@email',
181
+            name='name',
182
+            do_notify=False,
183
+            do_save=True,
184
+        )
185
+        u2 = api.create_user(
186
+            email='email2@email2',
187
+            name='name2',
188
+            do_notify=False,
189
+            do_save=True,
190
+        )
191
+        u3 = api.create_user(
192
+            email='notfound@notfound',
193
+            name='notfound',
194
+            do_notify=False,
195
+            do_save=True,
196
+        )
197
+        wapi = WorkspaceApi(
198
+            current_user=admin,
199
+            session=self.session,
200
+            config=self.app_config,
201
+        )
202
+        workspace = wapi.create_workspace(
203
+            'test workspace n°1',
204
+            save_now=True)
205
+        role_api = RoleApi(
206
+            current_user=admin,
207
+            session=self.session,
208
+            config=self.app_config,
209
+        )
210
+        role_api.create_one(u1, workspace, UserRoleInWorkspace.READER, False)
211
+        role_api.create_one(u2, workspace, UserRoleInWorkspace.READER, False)
212
+        role_api.create_one(u3, workspace, UserRoleInWorkspace.READER, False)
213
+        api2 = UserApi(
214
+            current_user=u1,
215
+            session=self.session,
216
+            config=self.config,
217
+        )
218
+        users = api2.get_known_user('name')
219
+        assert len(users) == 2
220
+        assert users[0] == u1
221
+        assert users[1] == u2
222
+
223
+    def test_unit__get_known__user__same_workspaces_users_by_email(self):
224
+        admin = self.session.query(models.User) \
225
+            .filter(models.User.email == 'admin@admin.admin') \
226
+            .one()
227
+        api = UserApi(
228
+            current_user=None,
229
+            session=self.session,
230
+            config=self.config,
231
+        )
232
+        u1 = api.create_user(
233
+            email='email@email',
234
+            name='name',
235
+            do_notify=False,
236
+            do_save=True,
237
+        )
238
+        u2 = api.create_user(
239
+            email='email2@email2',
240
+            name='name2',
241
+            do_notify=False,
242
+            do_save=True,
243
+        )
244
+        u3 = api.create_user(
245
+            email='notfound@notfound',
246
+            name='notfound',
247
+            do_notify=False,
248
+            do_save=True,
249
+        )
250
+        wapi = WorkspaceApi(
251
+            current_user=admin,
252
+            session=self.session,
253
+            config=self.app_config,
254
+        )
255
+        workspace = wapi.create_workspace(
256
+            'test workspace n°1',
257
+            save_now=True)
258
+        role_api = RoleApi(
259
+            current_user=admin,
260
+            session=self.session,
261
+            config=self.app_config,
262
+        )
263
+        role_api.create_one(u1, workspace, UserRoleInWorkspace.READER, False)
264
+        role_api.create_one(u2, workspace, UserRoleInWorkspace.READER, False)
265
+        role_api.create_one(u3, workspace, UserRoleInWorkspace.READER, False)
266
+        api2 = UserApi(
267
+            current_user=u1,
268
+            session=self.session,
269
+            config=self.config,
270
+        )
271
+        users = api2.get_known_user('email')
272
+        assert len(users) == 2
273
+        assert users[0] == u1
274
+        assert users[1] == u2
275
+
276
+    def test_unit__get_known__user__admin__by_name(self):
277
+        api = UserApi(
278
+            current_user=None,
279
+            session=self.session,
280
+            config=self.config,
281
+        )
282
+        u1 = api.create_user(
283
+            email='email@email',
284
+            name='name',
285
+            do_notify=False,
286
+            do_save=True,
287
+        )
288
+
289
+        users = api.get_known_user('nam')
290
+        assert len(users) == 1
291
+        assert users[0] == u1
292
+
110 293
     def test_unit__get_one__ok__nominal_case(self):
111 294
         api = UserApi(
112 295
             current_user=None,

+ 13 - 0
backend/tracim_backend/views/core_api/schemas.py View File

@@ -2,6 +2,7 @@
2 2
 import marshmallow
3 3
 from marshmallow import post_load
4 4
 from marshmallow.validate import OneOf
5
+from marshmallow.validate import Length
5 6
 from marshmallow.validate import Range
6 7
 
7 8
 from tracim_backend.lib.utils.utils import DATETIME_FORMAT
@@ -11,6 +12,7 @@ from tracim_backend.models.contents import CONTENT_STATUS
11 12
 from tracim_backend.models.contents import CONTENT_TYPES
12 13
 from tracim_backend.models.contents import open_status
13 14
 from tracim_backend.models.context_models import ActiveContentFilter
15
+from tracim_backend.models.context_models import AutocompleteQuery
14 16
 from tracim_backend.models.context_models import ContentIdsQuery
15 17
 from tracim_backend.models.context_models import UserWorkspaceAndContentPath
16 18
 from tracim_backend.models.context_models import ContentCreation
@@ -292,6 +294,17 @@ class CommentsPathSchema(WorkspaceAndContentIdPathSchema):
292 294
         return CommentPath(**data)
293 295
 
294 296
 
297
+class AutocompleteQuerySchema(marshmallow.Schema):
298
+    acp = marshmallow.fields.Str(
299
+        example='test',
300
+        description='search text to query',
301
+        validate=Length(min=2),
302
+    )
303
+    @post_load
304
+    def make_autocomplete(self, data):
305
+        return AutocompleteQuery(**data)
306
+
307
+
295 308
 class PageQuerySchema(marshmallow.Schema):
296 309
     page = marshmallow.fields.Int(
297 310
         example=2,

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

@@ -18,6 +18,8 @@ from tracim_backend.lib.utils.authorization import require_profile
18 18
 from tracim_backend.exceptions import WrongUserPassword
19 19
 from tracim_backend.exceptions import PasswordDoNotMatch
20 20
 from tracim_backend.views.core_api.schemas import UserSchema
21
+from tracim_backend.views.core_api.schemas import AutocompleteQuerySchema
22
+from tracim_backend.views.core_api.schemas import UserDigestSchema
21 23
 from tracim_backend.views.core_api.schemas import SetEmailSchema
22 24
 from tracim_backend.views.core_api.schemas import SetPasswordSchema
23 25
 from tracim_backend.views.core_api.schemas import UserInfosSchema
@@ -37,6 +39,7 @@ from tracim_backend.models.contents import CONTENT_TYPES
37 39
 SWAGGER_TAG__USER_ENDPOINTS = 'Users'
38 40
 
39 41
 
42
+
40 43
 class UserController(Controller):
41 44
 
42 45
     @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
@@ -77,6 +80,46 @@ class UserController(Controller):
77 80
         return uapi.get_user_with_context(request.candidate_user)
78 81
 
79 82
     @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
83
+    @require_profile(Group.TIM_ADMIN)
84
+    @hapic.output_body(UserDigestSchema(many=True))
85
+    def users(self, context, request: TracimRequest, hapic_data=None):
86
+        """
87
+        Get all users
88
+        """
89
+        app_config = request.registry.settings['CFG']
90
+        uapi = UserApi(
91
+            current_user=request.current_user,  # User
92
+            session=request.dbsession,
93
+            config=app_config,
94
+        )
95
+        users = uapi.get_all()
96
+        context_users = [
97
+            uapi.get_user_with_context(user) for user in users
98
+        ]
99
+        return context_users
100
+
101
+    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
102
+    @require_same_user_or_profile(Group.TIM_MANAGER)
103
+    @hapic.input_path(UserIdPathSchema())
104
+    @hapic.input_query(AutocompleteQuerySchema())
105
+    @hapic.output_body(UserDigestSchema(many=True))
106
+    def known_members(self, context, request: TracimRequest, hapic_data=None):
107
+        """
108
+        Get known users list
109
+        """
110
+        app_config = request.registry.settings['CFG']
111
+        uapi = UserApi(
112
+            current_user=request.candidate_user,  # User
113
+            session=request.dbsession,
114
+            config=app_config,
115
+        )
116
+        users = uapi.get_known_user(acp=hapic_data.query.acp)
117
+        context_users = [
118
+            uapi.get_user_with_context(user) for user in users
119
+        ]
120
+        return context_users
121
+
122
+    @hapic.with_api_doc(tags=[SWAGGER_TAG__USER_ENDPOINTS])
80 123
     @hapic.handle_exception(WrongUserPassword, HTTPStatus.FORBIDDEN)
81 124
     @require_same_user_or_profile(Group.TIM_ADMIN)
82 125
     @hapic.input_body(SetEmailSchema())
@@ -384,6 +427,14 @@ class UserController(Controller):
384 427
         configurator.add_route('user', '/users/{user_id}', request_method='GET')  # nopep8
385 428
         configurator.add_view(self.user, route_name='user')
386 429
 
430
+        # users lists
431
+        configurator.add_route('users', '/users', request_method='GET')  # nopep8
432
+        configurator.add_view(self.users, route_name='users')
433
+
434
+        # known members lists
435
+        configurator.add_route('known_members', '/users/{user_id}/known_members', request_method='GET')  # nopep8
436
+        configurator.add_view(self.known_members, route_name='known_members')
437
+
387 438
         # set user email
388 439
         configurator.add_route('set_user_email', '/users/{user_id}/email', request_method='PUT')  # nopep8
389 440
         configurator.add_view(self.set_user_email, route_name='set_user_email')